Android:如何从后台服务中截取网页的“屏幕截图”?

3
我有一个网页的URL地址,我想在后台获取该网页的截屏,例如在Service中,并且向用户显示UI。
我尝试在我的Service中创建一个WebView,然后使用capturePicture()方法在页面加载完成后获取截图,但是创建的Picture(和我从中创建的Bitmap)总是为空的。(这在普通Activity中完美地工作,但不适用于我的后台Service)。
是否有办法使其正常工作,或者有其他方法可以在没有UI的情况下获取网页的“截图”?
1个回答

4

注:本答案过时 - 我使用的最新Android版本是4.4,在其他未经测试的Android版本或设备上可能会有所不同...这也是一个超级复杂的黑客攻击 - 现在我建议使用web服务/API。


搞定了,我必须设置WebView的“大小”,以便生成的“屏幕截图”不是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://stackoverflow.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() {

}


}

你如何启动这个服务并调用它? - Shimon Doodkin
2
@ShimonDoodkin 这样的代码:Intent intent = new Intent(this, SaveService.class); intent.putExtra(Intent.EXTRA_TEXT, "http://somewebsite.com/somepage");。还要注意这里有一个更好/更新的版本的代码:https://github.com/JonasCz/save-for-offline/blob/master/app/src/main/java/jonas/tool/saveForOffline/ScreenshotService.java - Jonas Czech
起初它没有工作,然后这样做:onCreate() { ... mServiceHandler = new ServiceHandler(Looper.getMainLooper()); - Shimon Doodkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接