可能是重复问题:
如何在Android设备上以编程方式进行屏幕截图?
如何捕获Android设备屏幕内容并使用快照数据创建图像文件?我应该使用哪个API或在哪里可以找到相关资源?
顺便说一下: 不是相机快照,而是设备屏幕。
可能是重复问题:
如何在Android设备上以编程方式进行屏幕截图?
如何捕获Android设备屏幕内容并使用快照数据创建图像文件?我应该使用哪个API或在哪里可以找到相关资源?
顺便说一下: 不是相机快照,而是设备屏幕。
使用以下代码:
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);
}
});
希望这可以帮到你!对于更新的 Android 平台,可以在不需要 root 权限的情况下执行系统实用程序 screencap
,以获取屏幕截图。该命令位于 /system/bin
目录下。
您可以尝试在 adb 或任何 shell 下使用 /system/bin/screencap -h
命令来了解如何使用它。
顺便说一句,我认为这种方法只适用于单个快照。如果我们想要捕获多个帧以进行屏幕播放,那将会太慢。我不知道是否存在其他更快的屏幕截取方法。
[基于Android源代码:]
在C++端,SurfaceFlinger实现了captureScreen API。这通过binder 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 。要从应用程序创建截屏,应用程序必须具有 READ_FRAME_BUFFER
权限。
但即使如此,显然只能从系统应用程序创建屏幕截图,即与系统签名相同的应用程序。(这一部分我仍不太理解,因为我对 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;
}
Framebuffer似乎是一个不错的选择,但它不总是像Ryan Conrad所说的那样包含2个或以上的帧。在我的情况下,它仅包含一个帧。我猜这取决于帧/显示尺寸。
我试图连续读取framebuffer,但它似乎只返回固定数量的字节。在我的情况下,这是(3,410,432)字节,足以存储854 * 480 RGBA(3,279,360字节)的显示帧。是的,从fb0输出的帧在我的设备上是RGBA二进制格式。 这很可能因设备而异。这对您来解码它很重要=)
在我的设备上,/dev/graphics/fb0权限只有root用户和组图形(graphics)的用户可以读取fb0。graphics是受限制的组,因此您可能只能使用su命令在已root的手机上访问fb0。
Android应用程序具有用户ID(uid) app_##和组ID(guid) app_##。
adb shell具有uid shell和guid shell,它比应用程序具有更多的权限。您实际上可以在/system/permissions/platform.xml中检查这些权限。
这意味着您可以在adb shell中读取fb0而无需root,但是您将无法在应用程序中读取它。
此外,在AndroidManifest.xml中授予READ_FRAME_BUFFER和/或ACCESS_SURFACE_FLINGER权限对于常规应用程序无效,因为这些权限仅适用于“签名”应用程序。
如果您想在Android应用程序中从Java代码进行屏幕截图,据我所知,您必须具有Root权限。
onPageFinished()
方法中添加了一个处理程序,它有1秒的延迟。所以,如果它不起作用,你可能需要增加延迟时间。 - Nirav Dangi