Android:将WebView输出加载到应用程序小部件

Android:将WebView输出加载到应用程序小部件,android,webview,imageview,android-appwidget,appwidgetprovider,Android,Webview,Imageview,Android Appwidget,Appwidgetprovider,虽然我理解an不直接支持网络视图,但是否可以使用图像视图(受支持)和所述技术为图像视图生成图像?WebView不能直接使用,只能在后台使用,以便为ImageView提供图像。显然,至少在我的设备上,这是可能的,尽管您的里程可能会有所不同 在清单中,我们正常注册小部件的,还注册处理WebView及其图像捕获的服务 <manifest ... > ... <uses-permission android:name="android.permission.INTER

虽然我理解an不直接支持
网络视图
,但是否可以使用
图像视图
(受支持)和所述技术为
图像视图
生成图像?
WebView
不能直接使用,只能在后台使用,以便为
ImageView
提供图像。显然,至少在我的设备上,这是可能的,尽管您的里程可能会有所不同

在清单中,我们正常注册小部件的
,还注册处理
WebView
及其图像捕获的
服务

<manifest ... >
    ...

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

    <application ... >
        ...

        <receiver
            android:name=".WebWidgetProvider"
            android:label="@string/widget_name" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget_info" />
        </receiver>

        <service android:name=".WebShotService" />

    </application>

</manifest>
对于本例,小部件的布局,
Widget\u layout.xml
,只是一个
ImageView。

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget_image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="fitXY"
    android:src="@drawable/ic_launcher" />
服务
中,我们实例化了一个
WebView
,并将其添加到
FrameLayout
,然后将其宽度和高度参数添加到
WindowManager
。然后,我们在
WebView
中加载一个测试URL,当页面完成时,我们强制
WebView
以适当的大小进行布局,并通过
画布
对象将其绘制到目标
位图
。这是在稍微延迟后完成的,以允许
WebView
完全渲染自身,以免最终得到一个空白的白色图像。然后在
远程视图
对象上设置
位图
,以更新小部件布局中的
图像视图
。出于测试目的,我在代码中留下了一个
Toast
,因为我们的示例小部件的更新频率可能比Stack Overflow的首页刷新频率更高

public class WebShotService extends Service {
    private WebView webView;
    private WindowManager winManager;

    public int onStartCommand(Intent intent, int flags, int startId) {
        winManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        webView = new WebView(this);
        webView.setVerticalScrollBarEnabled(false);
        webView.setWebViewClient(client);

        final WindowManager.LayoutParams params =
            new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
                                           WindowManager.LayoutParams.WRAP_CONTENT,
                                           WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                                           WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                                           PixelFormat.TRANSLUCENT);
        params.x = 0;
        params.y = 0;
        params.width = 0;
        params.height = 0;

        final FrameLayout frame = new FrameLayout(this);
        frame.addView(webView);
        winManager.addView(frame, params);

        webView.loadUrl("http://stackoverflow.com");

        return START_STICKY;
    }

    private final WebViewClient client = new WebViewClient() {
        public void onPageFinished(WebView view, String url) {
            final Point p = new Point();
            winManager.getDefaultDisplay().getSize(p);

            webView.measure(MeasureSpec.makeMeasureSpec((p.x < p.y ? p.y : p.x),
                                MeasureSpec.EXACTLY), 
                            MeasureSpec.makeMeasureSpec((p.x < p.y ? p.x : p.y),
                                MeasureSpec.EXACTLY));
            webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight());

            webView.postDelayed(capture, 1000);
        }
    };

    private final Runnable capture = new Runnable() {
        @Override
        public void run() {
            try {
                final Bitmap bmp = Bitmap.createBitmap(webView.getWidth(),
                    webView.getHeight(), Bitmap.Config.ARGB_8888);
                final Canvas c = new Canvas(bmp);
                webView.draw(c);

                updateWidgets(bmp);
            }
            catch (IllegalArgumentException e) {
                e.printStackTrace();
            }

            stopSelf();
        }
    };

    private void updateWidgets(Bitmap bmp) {
        final AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
        final int[] ids = widgetManager.getAppWidgetIds(
            new ComponentName(this, WebWidgetProvider.class));

        if (ids.length < 1) {
            return;
        }

        final RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget_layout);
        views.setImageViewBitmap(R.id.widget_image, bmp);
        widgetManager.updateAppWidget(ids, views);

        Toast.makeText(this, "WebWidget Update", 0).show();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
公共类WebShotService扩展服务{
私有网络视图;
专用WindowManager winManager;
公共int onStartCommand(Intent Intent、int标志、int startId){
winManager=(WindowManager)getSystemService(Context.WINDOW\u服务);
webView=新的webView(此);
webView.setVerticalScrollBarEnabled(false);
setWebViewClient(客户端);
最终WindowManager.LayoutParams参数=
新建WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_内容,
WindowManager.LayoutParams.WRAP_内容,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_不可触摸,
像素格式(半透明);
参数x=0;
参数y=0;
参数宽度=0;
参数高度=0;
最终框架布局框架=新框架布局(本);
frame.addView(webView);
winManager.addView(框架,参数);
webView.loadUrl(“http://stackoverflow.com");
返回开始时间;
}
私有最终WebViewClient客户端=新WebViewClient(){
公共void onPageFinished(WebView视图,字符串url){
最终点p=新点();
winManager.getDefaultDisplay().getSize(p);
webView.measure(MeasureSpec.makeMeasureSpec((p.x
这是Widgety Goods的截图


在上述答案的基础上

对于出现此错误的用户-无法添加窗口。此窗口类型的权限被拒绝至少在我的情况下,如果设备运行棉花糖,则需要更改类型

简单地替换


WindowManager.LayoutParams.键入系统覆盖


WindowManager.LayoutParams.TYPE_TOAST(或)


WindowManager.LayoutParams.TYPE_APPLICATION_面板

它会工作得非常好

注意:已通过运行最新版本marsmallow的Nexus6p进行检查和确认。

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY需要权限android.permission.INTERNAL_SYSTEM_窗口,只能为android系统相关应用添加该窗口

另外,对于希望使用Javascript解析数据的用户,在onPageFinished()加载完页面后,不要忘记更改web视图的高度和宽度

在上面的回答中,我完全忽略了这一点的重要性,结果浪费了很多时间

最初我的假设是因为我的要求不是在web视图中显示内容
public class WebWidgetProvider extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // We can't trust the appWidgetIds param here, as we're using
        // ACTION_APPWIDGET_UPDATE to trigger our own updates, and
        // Widgets might've been removed/added since the alarm was last set.
        final int[] currentIds = appWidgetManager.getAppWidgetIds(
            new ComponentName(context, WebWidgetProvider.class));

        if (currentIds.length < 1) {
            return;
        }

        // We attach the current Widget IDs to the alarm Intent to ensure its
        // broadcast is correctly routed to onUpdate() when our AppWidgetProvider
        // next receives it.
        Intent iWidget = new Intent(context, WebWidgetProvider.class)
            .setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
            .putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, currentIds);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, iWidget, 0);

        ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE))
            .setExact(AlarmManager.RTC, System.currentTimeMillis() + 30000, pi);

        Intent iService = new Intent(context, WebShotService.class);
        context.startService(iService);
    }
}
public class WebShotService extends Service {
    private WebView webView;
    private WindowManager winManager;

    public int onStartCommand(Intent intent, int flags, int startId) {
        winManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        webView = new WebView(this);
        webView.setVerticalScrollBarEnabled(false);
        webView.setWebViewClient(client);

        final WindowManager.LayoutParams params =
            new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
                                           WindowManager.LayoutParams.WRAP_CONTENT,
                                           WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                                           WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                                           PixelFormat.TRANSLUCENT);
        params.x = 0;
        params.y = 0;
        params.width = 0;
        params.height = 0;

        final FrameLayout frame = new FrameLayout(this);
        frame.addView(webView);
        winManager.addView(frame, params);

        webView.loadUrl("http://stackoverflow.com");

        return START_STICKY;
    }

    private final WebViewClient client = new WebViewClient() {
        public void onPageFinished(WebView view, String url) {
            final Point p = new Point();
            winManager.getDefaultDisplay().getSize(p);

            webView.measure(MeasureSpec.makeMeasureSpec((p.x < p.y ? p.y : p.x),
                                MeasureSpec.EXACTLY), 
                            MeasureSpec.makeMeasureSpec((p.x < p.y ? p.x : p.y),
                                MeasureSpec.EXACTLY));
            webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight());

            webView.postDelayed(capture, 1000);
        }
    };

    private final Runnable capture = new Runnable() {
        @Override
        public void run() {
            try {
                final Bitmap bmp = Bitmap.createBitmap(webView.getWidth(),
                    webView.getHeight(), Bitmap.Config.ARGB_8888);
                final Canvas c = new Canvas(bmp);
                webView.draw(c);

                updateWidgets(bmp);
            }
            catch (IllegalArgumentException e) {
                e.printStackTrace();
            }

            stopSelf();
        }
    };

    private void updateWidgets(Bitmap bmp) {
        final AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
        final int[] ids = widgetManager.getAppWidgetIds(
            new ComponentName(this, WebWidgetProvider.class));

        if (ids.length < 1) {
            return;
        }

        final RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget_layout);
        views.setImageViewBitmap(R.id.widget_image, bmp);
        widgetManager.updateAppWidget(ids, views);

        Toast.makeText(this, "WebWidget Update", 0).show();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}