【问题标题】:How to take a screenshot and share it programmatically如何截取屏幕截图并以编程方式共享
【发布时间】:2019-04-10 11:46:10
【问题描述】:

我正在 Android 中制作一个应用程序,我必须在其中截取我的一项活动的屏幕截图并将其作为附件邮寄。

我想截取当前页面,然后通过电子邮件、蓝牙、Twitter 或 Facebook 分享。

我的代码如下:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.menuselected1, menu);
  return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

  switch (item.getItemId()) {
    case R.id.ScreenShot:

    try {
        takeScreenShot(this);
    }
    catch (Exception e) {
        System.out.println(e);
    }

    return true;

    default:
    return super.onOptionsItemSelected(item);
  }
}

private static void savePic(Bitmap b, String strFileName) {
  FileOutputStream fos = null;
  try {
      fos = new FileOutputStream(strFileName);
      if (null != fos) {
        b.compress(Bitmap.CompressFormat.PNG, 90, fos);
        System.out.println("b is:"+b);
        fos.flush();
        fos.close();
      }
  } catch (FileNotFoundException e) {
          e.printStackTrace();
  } catch (IOException e) {
          e.printStackTrace();
  }
}

public static void shoot(Activity a,String b) {
  //savePic(takeScreenShot(a), "sdcard/xx.png");
  savePic(takeScreenShot(a), b);
}

private static Bitmap takeScreenShot(Activity activity) {
  View view = activity.getWindow().getDecorView();
  view.setDrawingCacheEnabled(true);
  view.buildDrawingCache();
  Bitmap b1 = view.getDrawingCache();
  Rect frame = new Rect();
  activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
  int statusBarHeight = frame.top;
  int width = activity.getWindowManager().getDefaultDisplay().getWidth();
  int height = activity.getWindowManager().getDefaultDisplay()
               .getHeight();

  // Bitmap b = Bitmap.createBitmap(b1, 0, 25, 320, 455);
  Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height
                                 - statusBarHeight);
  view.destroyDrawingCache();
  return b;
}

【问题讨论】:

    标签: android screenshot


    【解决方案1】:

    试试这个来截取当前活动的截图:

    Android 2.2:

    private static Bitmap takeScreenShot(Activity activity)
    {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap b1 = view.getDrawingCache();
        Rect frame = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;
    
        DisplayMetrics displaymetrics = new DisplayMetrics(); 
        mContext.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    
        int width = displaymetrics.widthPixels;
        int height = displaymetrics.heightPixels;
    
        Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height  - statusBarHeight);
        view.destroyDrawingCache();
        return b;
    }
    private static void savePic(Bitmap b, String strFileName)
    {
        FileOutputStream fos = null;
        try
        {
            fos = new FileOutputStream(strFileName);
            if (null != fos)
            {
                b.compress(Bitmap.CompressFormat.PNG, 90, fos);
                fos.flush();
                fos.close();
            }
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    

    【讨论】:

    • 我正在开发 android2.2,我使用了你的代码,但它没有显示任何内容,这意味着我想知道图像在手机中的存储位置
    • 建议使用缓冲流包装您的输出流。
    • 这仅适用于有根设备,是否适用于无根设备?
    【解决方案2】:

    如果“当前页面截图”是指“我的一项活动的截图”,您可以安排到render your Views to a bitmap-backed Canvas, then save an image from the bitmap

    如果“当前页面的屏幕截图”是指“其他人活动的屏幕截图”,那么出于隐私和安全原因,Android SDK 不支持该功能。 root 设备用户可以使用多种技术来截取屏幕截图。

    【讨论】:

    • 我想让它截取我的活动截图
    • 为什么不在连接手机的 Eclipse 中使用 DDMS?我知道这不是“代码解决方案”,但你的问题听起来有点奇怪。
    【解决方案3】:

    1。创建分享按钮

    我想在操作栏中使用我的,所以我创建了一个 share_menu.xml 文件:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item
            android:id="@+id/share_item"
            app:showAsAction="always|withText"
            android:title="Share"
            android:icon="@drawable/share_icon"
            android:actionProviderClass=
                "android.widget.ShareActionProvider" />
    </menu>
    

    这会在操作栏中添加一个带有我的 share_icon 和文本的按钮。

    2。将共享菜单添加到您的活动(或片段)

    我在片段中执行此操作,因此我将以下代码添加到我的片段文件中。如果你在一个活动中,那么你会覆盖public boolean onCreateOptionsMenu(Menu menu)

    @Override
    public void onCreateOptionsMenu(
            Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.share_menu, menu);
    }
    

    如果您使用片段执行此操作,则必须在 onCreate() 中添加:

    setHasOptionsMenu(true);
    

    3。设置按钮操作/回调/onclick

    这就是分享的开始。

    @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            if (item.getItemId() == R.id.share_item){
                Bitmap bm = screenShot(this.getView());
                File file = saveBitmap(bm, "mantis_image.png");
                Log.i("chase", "filepath: "+file.getAbsolutePath());
                Uri uri = Uri.fromFile(new File(file.getAbsolutePath()));
                Intent shareIntent = new Intent();
                shareIntent.setAction(Intent.ACTION_SEND);
                shareIntent.putExtra(Intent.EXTRA_TEXT, "Check out my app.");
                shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
                shareIntent.setType("image/*");
                shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                startActivity(Intent.createChooser(shareIntent, "share via"));
            }
            return super.onOptionsItemSelected(item);
        }
    

    注意这会调用两个魔法方法:

    screenShot():

    private Bitmap screenShot(View view) {
        Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        view.draw(canvas);
        return bitmap;
    }
    
    private static File saveBitmap(Bitmap bm, String fileName){
        final String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Screenshots";
        File dir = new File(path);
        if(!dir.exists())
            dir.mkdirs();
        File file = new File(dir, fileName);
        try {
            FileOutputStream fOut = new FileOutputStream(file);
            bm.compress(Bitmap.CompressFormat.PNG, 90, fOut);
            fOut.flush();
            fOut.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;
    }
    

    重要

    到您的AndroidManifest.xml,您必须添加:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    

    否则屏幕截图将不会保存,gmail 会认为您正在尝试附加一个空文件。

    此外,很多 SO 答案都说使用 "*/*" 代替 shareIntent.setType() 但这会导致 Facebook 共享出现问题,因此最好将其保留为 "image/*"

    【讨论】:

    • 这在棉花糖中不起作用。关于如何在棉花糖中解决这个问题的任何想法。对于 kitkat,它运行良好。
    • @VarshaVijayvargiya,我没试过但是有权限,请注意你必须在android M运行时询问权限。
    【解决方案4】:

    带有权限检查的 Kotlin 完整解决方案代码:

    1- 使用这个不错的库来截取带有 java / Kotlin / Rx 功能的屏幕截图,添加库依赖:InstaCapture github link

     implementation "com.github.tarek360:instacapture:2.0.1"
    

    2- 必须检查所有 android 版本的兼容性:

         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                ) != PackageManager.PERMISSION_GRANTED
            ) { // Needs permission so request it
                DeviceUtil.showAlertMsg(this, GeneralDicModel.shareMsgScreenShot!!)
                requestPermissions(
                    arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                    PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
                )   //callback  result to onRequestPermissionsResult
            } else { //Has got the permission before or doesn't need
                screenShotAndShareIt()
            }
    

    3- 查看权限结果:

     override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<out String>,
        grantResults: IntArray
    ) {
        when (requestCode) {
            PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    screenShotAndShareIt()
                } else {
                    //  toast("Permission must be granted in order to save scrrenshot file")
                }
            }
        }
    }
    

    4- Func 调用截图并按意图分享:

     fun screenShotAndShareIt() {
        Instacapture.capture(this, object : SimpleScreenCapturingListener() {
        override fun onCaptureComplete(bitmap: Bitmap) {
        val state = Environment.getExternalStorageState()
                if (Environment.MEDIA_MOUNTED == state) {
                    val path: String = Environment.getExternalStorageDirectory().toString()  
                    val picDir = File(path.plus("/myPic"))
                    if (!picDir.exists()) {
                        picDir.mkdir()
                    }
                    var bitmapScreenShot = bitmap
                    val fileName = "screenshot" + ".jpg"
                    val picFile = File(picDir.path.plus("/" + fileName))
                    try {
                        picFile.createNewFile()
                        val picOut = FileOutputStream(picFile)
                        bitmapScreenShot =
                            Bitmap.createBitmap(bitmapScreenShot, 0, 0, bitmapScreenShot.width, bitmapScreenShot.height)
                        val saved: Boolean = bitmapScreenShot.compress(Bitmap.CompressFormat.JPEG, 100, picOut)
                        if (saved) {
                            Log.i(
                                TAG,
                                "ScreenShotAndShareIt : Image saved to your device Pictures " + "directory! + ${picFile.absolutePath}"
                            )
                        } else {
                            Log.i(TAG, "ScreenShotAndShareIt Error on Save! + ${picFile.absolutePath}")
                        }
                        picOut.close()
    
                        // share via intent
                        val intent: Intent = Intent(android.content.Intent.ACTION_SEND)
                        intent.type = "image/jpeg"
                        intent.putExtra(Intent.EXTRA_STREAM, Uri.parse(picFile.absolutePath))
                        startActivity(Intent.createChooser(intent, "Sharing"))
                    } catch (e: Exception) {
                        Log.i(TAG, "ScreenShotAndShareIt Error catch : " + e.printStackTrace())
                    }
                } else {
                    //Error
                    Log.i(TAG, "ScreenShotAndShareIt Error Environment.MEDIA_MOUNTED == state : " )
                }
     }
     })
    

    5- 声明这个变量:

    val PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 100
    

    6- 不要忘记将此权限添加到 AndroidManifest.xml:

        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    

    【讨论】:

      【解决方案5】:

      这就是我捕获屏幕并共享它的方式。有兴趣的可以看看。

      public Bitmap takeScreenshot() {
        View rootView = findViewById(android.R.id.content).getRootView();
        rootView.setDrawingCacheEnabled(true);
      return rootView.getDrawingCache();
       }
      

      以及将位图图像保存到外部存储的方法:

      public void saveBitmap(Bitmap bitmap) {
        File imagePath = new File(Environment.getExternalStorageDirectory() +       "/screenshot.png");
        FileOutputStream fos;
        try {
        fos = new FileOutputStream(imagePath);
        bitmap.compress(CompressFormat.JPEG, 100, fos);
       fos.flush();
       fos.close();
       } catch (FileNotFoundException e) {
      Log.e("GREC", e.getMessage(), e);
      } catch (IOException e) {
      Log.e("GREC", e.getMessage(), e);
      }}
      

      查看更多:https://www.youtube.com/watch?v=LRCRNvzamwY&feature=youtu.be

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-04-17
        • 1970-01-01
        • 2011-04-06
        • 1970-01-01
        • 2016-03-18
        • 2011-01-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多