如何捕捉Android设备的屏幕内容?
可能重复:
如何以编程方式在Android上截图?
如何捕捉Android设备的屏幕内容,并使用快照数据制作一个图像文件? 我应该使用哪个API或在哪里可以find相关资源?
BTW:不是相机快照,而是设备屏幕
根据这个链接 ,可以在android sdk的工具目录中使用ddms来获取屏幕截图。
为了在应用程序中(而不是在开发过程中)做到这一点,也有应用程序这样做。 但是@ zed_0xff指出它肯定需要root。
使用下面的代码:
Bitmap bitmap; View v1 = MyView.getRootView(); v1.setDrawingCacheEnabled(true); bitmap = Bitmap.createBitmap(v1.getDrawingCache()); v1.setDrawingCacheEnabled(false);
这里MyView
是我们需要在屏幕上包含的View
。 你也可以通过这种方式(没有getRootView()
)从任何View
获取DrawingCache
。
还有另一种方法..
如果我们将ScrollView
作为根视图,那么最好使用下面的代码,
LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE); FrameLayout root = (FrameLayout) inflater.inflate(R.layout.activity_main, null); // activity_main is UI(xml) file we used in our Activity class. FrameLayout is root view of my UI(xml) file. root.setDrawingCacheEnabled(true); Bitmap bitmap = getBitmapFromView(this.getWindow().findViewById(R.id.frameLayout)); // here give id of our root layout (here its my FrameLayout's id) root.setDrawingCacheEnabled(false);
这里是getBitmapFromView()
方法
public static Bitmap getBitmapFromView(View view) { //Define a bitmap with the same size as the view Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888); //Bind a canvas to it Canvas canvas = new Canvas(returnedBitmap); //Get the view's background Drawable bgDrawable =view.getBackground(); if (bgDrawable!=null) //has background drawable, then draw it on the canvas bgDrawable.draw(canvas); else //does not have background drawable, then draw white background on the canvas canvas.drawColor(Color.WHITE); // draw the view on the canvas view.draw(canvas); //return the bitmap return returnedBitmap; }
它将显示整个屏幕,包括隐藏在ScrollView
内容
更新于2016年4月20日
还有另一种更好的方式来截图。
这里我截取了WebView
截图。
WebView w = new WebView(this); w.setWebViewClient(new WebViewClient() { public void onPageFinished(final WebView webView, String url) { new Handler().postDelayed(new Runnable(){ @Override public void run() { webView.measure(View.MeasureSpec.makeMeasureSpec( View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight()); webView.setDrawingCacheEnabled(true); webView.buildDrawingCache(); Bitmap bitmap = Bitmap.createBitmap(webView.getMeasuredWidth(), webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); int height = bitmap.getHeight(); canvas.drawBitmap(bitmap, 0, height, paint); webView.draw(canvas); if (bitmap != null) { try { String filePath = Environment.getExternalStorageDirectory() .toString(); OutputStream out = null; File file = new File(filePath, "/webviewScreenShot.png"); out = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG, 50, out); out.flush(); out.close(); bitmap.recycle(); } catch (Exception e) { e.printStackTrace(); } } } }, 1000); } });
希望这可以帮助..!
AFAIK,目前捕捉android截图的所有方法都使用/ dev / graphics / fb0 framebuffer。 这包括ddms。 它需要root从这个stream中读取。 ddms使用adbd来请求信息,因此不需要root,因为adb具有从/ dev / graphics / fb0请求数据所需的权限。
framebuffer包含RGB565图像的2+“帧”。 如果你能够读取数据,你将不得不知道屏幕分辨率知道需要多less字节来获取图像。 每个像素是2个字节,所以如果屏幕资源是480×800,你将不得不读取图像768,000字节,因为480×800 RGB565图像有384,000像素。
对于较新的Android平台,可以在/ system / bin中执行系统工具“screencap”来获得没有root权限的屏幕截图。 您可以尝试“/ system / bin / screencap -h”来查看如何在adb或任何shell下使用它。
顺便说一句,我认为这种方法只适用于单一快照。 如果我们想要捕捉多个屏幕播放帧,它会太慢。 我不知道是否有任何其他方法更快的屏幕捕获。
[基于Android的源代码:]
在C ++端,SurfaceFlinger实现了CaptureScreen API。 这暴露在活页夹IPC界面上,每次返回一个新的包含来自屏幕的原始像素的ashmem区域。 实际的截图是通过OpenGL进行的。
对于系统C ++客户端来说,接口是通过ScreenshotClient类公开的,在Android <4.1中定义在<surfaceflinger_client/SurfaceComposerClient.h>
中; 对于Android> 4.1使用<gui/SurfaceComposerClient.h>
在JB之前,要在C ++程序中进行截图,这已经足够了:
ScreenshotClient ssc; ssc.update();
随着JB和多个显示器,它变得稍微复杂:
ssc.update( android::SurfaceComposerClient::getBuiltInDisplay( android::ISurfaceComposer::eDisplayIdMain));
然后你可以访问它:
do_something_with_raw_bits(ssc.getPixels(), ssc.getSize(), ...);
使用Android源代码,您可以编译自己的共享库来访问该API,然后通过JNI将其展示给Java。 要从您的应用创build屏幕截图,应用必须具有READ_FRAME_BUFFER
权限。 但即使如此,显然你只能从系统应用程序创build屏幕截图,也就是使用与系统相同的密钥进行签名。 (这部分我还是不太明白,因为我对Android权限系统不够熟悉。)
这里是JB 4.1 / 4.2的一段代码:
#include <utils/RefBase.h> #include <binder/IBinder.h> #include <binder/MemoryHeapBase.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> static void do_save(const char *filename, const void *buf, size_t size) { int out = open(filename, O_RDWR|O_CREAT, 0666); int len = write(out, buf, size); printf("Wrote %d bytes to out.\n", len); close(out); } int main(int ac, char **av) { android::ScreenshotClient ssc; const void *pixels; size_t size; int buffer_index; if(ssc.update( android::SurfaceComposerClient::getBuiltInDisplay( android::ISurfaceComposer::eDisplayIdMain)) != NO_ERROR ){ printf("Captured: w=%d, h=%d, format=%d\n"); ssc.getWidth(), ssc.getHeight(), ssc.getFormat()); size = ssc.getSize(); do_save(av[1], pixels, size); } else printf(" screen shot client Captured Failed"); return 0; }
您可以尝试以下库: http : //code.google.com/p/android-screenshot-library/ Android Screenshot Library(ASL)能够以编程方式捕获Android设备的屏幕截图,而不需要具有root访问权限。 相反,ASL利用在后台运行的本地服务,每个设备启动时通过Androiddebugging桥(ADB)启动一次。
如果您想在Android应用程序AFAIK中从Java代码执行屏幕截图,则必须拥有根特权。
Framebuffer似乎要走了,它不会像Ryan Conrad所说的那样总是包含2帧。 在我的情况下,它只包含一个。 我想这取决于帧/显示器的大小。
我试图不断读取framebuffer,但似乎返回固定数量的字节读取。 在我的情况下(3 410 432)字节,这足以存储854 * 480 RGBA(3 279 360字节)的显示帧。 是的, 从fb0输出的二进制帧是我的设备中的RGBA 。 这很可能取决于设备之间的设备 。 这对你来说是很重要的解码=)
在我的设备/ dev / graphics / fb0权限是这样的, 只有 组和graphics用户可以读取 fb0。 graphics是一个受限制的组,所以你可能只能使用su命令访问带有根的手机的fb0。
Android应用程序具有用户标识(uid)app _ ##和组标识(guid)app _ ## 。
adb shell有uid shell和guid shell ,比应用程序拥有更多的权限。 您实际上可以在/system/permissions/platform.xml中检查这些权限
这意味着你将能够在没有root权限的情况下在adb shell中读取fb0,但是不会在没有root权限的应用程序中读取它。
此外,在AndroidManifest.xml中授予READ_FRAME_BUFFER和/或ACCESS_SURFACE_FLINGER权限对于常规应用程序无效,因为这些只适用于“签名”应用程序。