【问题标题】:Android - How to take screenshot programmaticallyAndroid - 如何以编程方式截取屏幕截图
【发布时间】:2013-11-22 02:52:35
【问题描述】:

当我的应用程序安装并在后台每 200 毫秒运行时,我需要以编程方式截取 Android 设备或模拟器的屏幕截图,并将图像保存在我的计算机中。我已经使用以下代码实现了此过程,并且仅在我的应用程序处于前台时才有效。当我的应用程序在后台时,我也想截屏。以下是我的代码:

public static Bitmap takeScreenshot(Activity activity, int ResourceID) { 
    Random r = new Random();
    int iterator=r.nextInt();   
     String mPath = Environment.getExternalStorageDirectory().toString() + "/screenshots/";
    View v1 = activity.getWindow().getDecorView().findViewById(ResourceID);
    v1.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    v1.layout(0, 0, v1.getMeasuredWidth(), v1.getMeasuredHeight()); 
    v1.setDrawingCacheEnabled(true);
    final Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
    Bitmap resultBitmap = Bitmap.createScaledBitmap(bitmap, 640, 480, false);
    v1.setDrawingCacheEnabled(false);
    File imageFile = new File(mPath);
    imageFile.mkdirs();
    imageFile = new File(imageFile+"/"+iterator+"_screenshot.png");
    try {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        resultBitmap.compress(CompressFormat.PNG, 100, bos);
        byte[] bitmapdata = bos.toByteArray();

        //write the bytes in file
        FileOutputStream fos = new FileOutputStream(imageFile);
        fos.write(bitmapdata);
        fos.flush();
        fos.close();    
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return bitmap;
    }  

如何以编程方式在Devices -> DDMS 中实现屏幕捕获的刷新和保存按钮的功能?我能做到吗?

【问题讨论】:

  • 如果这可能的话,我会吓坏的。这样做的应用会引发严重的安全问题。
  • 除非手机已root(kitkat,否则无法执行此操作。至于“严重的安全问题”,我认为其他地方存在更严重的安全问题。如果应用程序可以请求截取屏幕截图的权限,这没什么大不了的。
  • 这不是屏幕截图……这是每 200 毫秒的屏幕截图。本质上是一个 5 FPS 的视频。这将轻松捕获在手机上完成的所有内容。不反对为我自己的使用(制作应用程序的视频)而这样做,但授予第 3 方应用程序截取屏幕截图的权限将是一个漫长的兔子洞。
  • stackoverflow.com/a/54779181/7074112 检查此答案以获得可能的解决方案

标签: java android


【解决方案1】:

如果你的手机已经root了试试这个

Process sh = Runtime.getRuntime().exec("su", null,null);

                    OutputStream  os = sh.getOutputStream();
                    os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
                    os.flush();

                    os.close();
                    sh.waitFor();

然后将img.png读取为位图并将其转换为jpg如下

Bitmap screen = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+         
File.separator +"img.png");

//my code for saving
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    screen.compress(Bitmap.CompressFormat.JPEG, 15, bytes);

//you can create a new file name "test.jpg" in sdcard folder.

File f = new File(Environment.getExternalStorageDirectory()+ File.separator + "test.jpg");
            f.createNewFile();
//write the bytes in file
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(bytes.toByteArray());
// remember close de FileOutput

    fo.close();

如果您的应用程序在后台,除非您是 root,否则您无法访问屏幕,即使您在后台,上面的代码也可以最有效地截取任何屏幕。

更新

谷歌有一个库,你可以用它来截图而不生根,我试过了,但我相信它会尽快耗尽内存。

试试http://code.google.com/p/android-screenshot-library/

【讨论】:

  • 屏幕截图在模拟器中工作,但不能在真实设备中使用
  • 你的设备root了吗?
  • 不,当用户对列表项的 lisk 计划显示带有共享选项的详细视图时,我们需要保存该布局位图,然后我们需要保存该文件以实现其在模拟器中的工作并捕获屏幕和 sendmail 意图将其共享变为现实,但无法正常工作
  • 请将您的代码作为要点发布并分享链接
  • gist.github.com/anonymous/84d06ec6c2cc368a0627 请检查此 captureScreen 代码。在模拟器中,它的工作原理也在清单中的用户权限中提供 write_external_storage
【解决方案2】:

这里是这样做的方法。

Android taking Screen shots through code

结果输出:

public class CaptureScreenShots extends Activity {
    LinearLayout L1;
    ImageView image;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.screen_shots);
         L1 = (LinearLayout) findViewById(R.id.LinearLayout01);
            Button but = (Button) findViewById(R.id.munchscreen);
            but.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    View v1 = L1.getRootView();
                    v1.setDrawingCacheEnabled(true);
                    Bitmap bm = v1.getDrawingCache();
                    BitmapDrawable bitmapDrawable = new BitmapDrawable(bm);
                    image = (ImageView) findViewById(R.id.screenshots);
                    image.setBackgroundDrawable(bitmapDrawable);
                }
            });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.screen_shots, menu);
        return true;
    }

}

【讨论】:

  • 这不是只有在应用程序在前台时才有效吗?
  • new BitmapDrawable(bitmap) 构造函数已弃用。而是使用image.setImageBitmap(bm)
  • 如果视图层次结构中有 SurfaceView,这将不起作用,因为 SurfaceView 没有绘图缓存。您将在屏幕截图中看到一个黑色矩形。
【解决方案3】:

在后台拍摄屏幕截图(如 ADB)需要 groups=1003(graphics)。否则你只能得到你自己的过程的屏幕截图。因此,您只能在有根设备上执行此操作,或者通过运行 ADB 本地程序来执行此操作。

可以在https://android.googlesource.com/platform/frameworks/base/+/android-4.3_r2.3/cmds/screencap/找到本机 cpp 代码示例

如果你想用java代码来做,你需要访问Surface类的隐藏API:

/**
 * Like {@link #screenshot(int, int, int, int)} but includes all
 * Surfaces in the screenshot.
 *
 * @hide
 */
public static native Bitmap screenshot(int width, int height);

这两个在ICS发布后应该都可以,对于像GB这样的早期版本,您可以查看native cpp代码。

但是,在某些 Android 设备中,媒体系统和画布等的实现不是很好,因此在这种情况下,您无法捕获任何视频播放或任何表面视图内容。

【讨论】:

  • 需要注意的是,这个方法在 Android 4.3 及更高版本中被移除了。
【解决方案4】:

您可以考虑混合使用MediaProjectionAccessibilityService。第一个轻松截取屏幕截图,第二个始终“在”所有应用程序“上方”运行

教程如何在CODELABS中运行AccessibilityService

以上例子的完整来源HERE

THIS 答案中,您可以找到非常有用的Activity 代码。记得设置适当的完全透明Theme

<style name="Theme.AppCompat.Translucent" parent="Theme.AppCompat.NoActionBar">
    <item name="android:background">#00000000</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:colorBackgroundCacheHint">@null</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowAnimationStyle">@null</item>
</style>

然后在你的AccessibilityService 中循环startActivity 尽可能频繁,甚至更好 - 使用LocalBroadcastManager 通知Service Activity 截取屏幕截图并完成(所以Service 可以开始这个@987654336再次@)

我做了类似的事情(仅供内部使用)+ 使用 OCR 分析屏幕截图以从中获取文本。有点解析,当 not-your-app 以某种方式保护AccesibilityService 功能时(这种类型的Service 旨在帮助残疾人,例如在文本阅读中,通常可以访问TextViews)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2016-03-18
    相关资源
    最近更新 更多