Android: 从后台服务获取网页的'screenshot'?
Android: take a 'screenshot' of a web page from a background service?
我有一个网页的URL,我想在后台拍摄这个网页的'screenshot',例如。在服务中,并且 没有 向用户显示 UI。
我曾尝试在我的服务中创建一个 WebView,然后使用 capturePicture()
方法在页面加载完成时获取屏幕截图,但是创建的 Picture
(以及 Bitmap
I create from it ) 总是空的。 (这在正常 Activity 中非常有效,但在我的后台服务中却不行)。
有什么方法可以让它工作,或者有一种替代方法可以在没有 UI 的情况下获得网页的 'screenshot' 吗?
注意:这个答案是旧的 - 我试过的最新 Android 版本是 4.4,YMMV在其他 Android 版本或设备上我没有测试过... 这也是一个超级笨拙的 hack - 现在我建议使用网络服务 / API为此。
想通了,我必须设置 WebView 的 'size',这样生成的 'Screenshot' 就不是 0 x 0 大小。然后我必须直接从 WebView 的 绘图缓存 获取位图,因为 capturePicture()
在这里似乎不起作用。
package com.example.screenshot;
import android.app.*;
import android.content.*;
import android.widget.*;
import android.util.*;
import android.webkit.*;
import android.graphics.*;
import java.io.*;
import android.view.View.*;
import android.os.*;
import android.os.Process;
//this is an example of how to take a screenshot in a background service
//not very elegant, but it works (for me anyway)
public class ScreenshotService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private Message msg;
private WebView webview;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
webview = new WebView(ScreenshotService.this);
//without this toast message, screenshot will be blank, dont ask me why...
Toast.makeText(ScreenshotService.this, "Taking screenshot...", Toast.LENGTH_SHORT).show();
// This is the important code :)
webview.setDrawingCacheEnabled(true);
//width x height of your webview and the resulting screenshot
webview.measure(600, 400);
webview.layout(0, 0, 600, 400);
webview.loadUrl("http://whosebug.com");
webview.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
//without this method, your app may crash...
}
@Override
public void onPageFinished(WebView view, String url) {
new takeScreenshotTask().execute();
stopSelf();
}
});
}
}
private class takeScreenshotTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void[] p1) {
//allow the webview to render
synchronized (this) {try {wait(350);} catch (InterruptedException e) {}}
//here I save the bitmap to file
Bitmap b = webview.getDrawingCache();
File file = new File("/sdcard/example-screenshot.png");
OutputStream out;
try {
out = new BufferedOutputStream(new FileOutputStream(file));
b.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
} catch (IOException e) {
Log.e("ScreenshotService", "IOException while trying to save thumbnail, Is /sdcard/ writable?");
e.printStackTrace();
}
Toast.makeText(ScreenshotService.this, "Screenshot taken", Toast.LENGTH_SHORT).show();
return null;
}
}
//service related stuff below, its probably easyer to use intentService...
@Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
}
}
我有一个网页的URL,我想在后台拍摄这个网页的'screenshot',例如。在服务中,并且 没有 向用户显示 UI。
我曾尝试在我的服务中创建一个 WebView,然后使用 capturePicture()
方法在页面加载完成时获取屏幕截图,但是创建的 Picture
(以及 Bitmap
I create from it ) 总是空的。 (这在正常 Activity 中非常有效,但在我的后台服务中却不行)。
有什么方法可以让它工作,或者有一种替代方法可以在没有 UI 的情况下获得网页的 'screenshot' 吗?
注意:这个答案是旧的 - 我试过的最新 Android 版本是 4.4,YMMV在其他 Android 版本或设备上我没有测试过... 这也是一个超级笨拙的 hack - 现在我建议使用网络服务 / API为此。
想通了,我必须设置 WebView 的 'size',这样生成的 'Screenshot' 就不是 0 x 0 大小。然后我必须直接从 WebView 的 绘图缓存 获取位图,因为 capturePicture()
在这里似乎不起作用。
package com.example.screenshot;
import android.app.*;
import android.content.*;
import android.widget.*;
import android.util.*;
import android.webkit.*;
import android.graphics.*;
import java.io.*;
import android.view.View.*;
import android.os.*;
import android.os.Process;
//this is an example of how to take a screenshot in a background service
//not very elegant, but it works (for me anyway)
public class ScreenshotService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private Message msg;
private WebView webview;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
webview = new WebView(ScreenshotService.this);
//without this toast message, screenshot will be blank, dont ask me why...
Toast.makeText(ScreenshotService.this, "Taking screenshot...", Toast.LENGTH_SHORT).show();
// This is the important code :)
webview.setDrawingCacheEnabled(true);
//width x height of your webview and the resulting screenshot
webview.measure(600, 400);
webview.layout(0, 0, 600, 400);
webview.loadUrl("http://whosebug.com");
webview.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
//without this method, your app may crash...
}
@Override
public void onPageFinished(WebView view, String url) {
new takeScreenshotTask().execute();
stopSelf();
}
});
}
}
private class takeScreenshotTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void[] p1) {
//allow the webview to render
synchronized (this) {try {wait(350);} catch (InterruptedException e) {}}
//here I save the bitmap to file
Bitmap b = webview.getDrawingCache();
File file = new File("/sdcard/example-screenshot.png");
OutputStream out;
try {
out = new BufferedOutputStream(new FileOutputStream(file));
b.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
} catch (IOException e) {
Log.e("ScreenshotService", "IOException while trying to save thumbnail, Is /sdcard/ writable?");
e.printStackTrace();
}
Toast.makeText(ScreenshotService.this, "Screenshot taken", Toast.LENGTH_SHORT).show();
return null;
}
}
//service related stuff below, its probably easyer to use intentService...
@Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
}
}