Android:将WebView输出加载到App Widget中

虽然我很欣赏App Widget不直接支持WebView ,但是它是否可以使用ImageView (支持它),以及这里描述的技术为ImageView生成图像? WebView不会直接使用,而只会在后台使用,以便为ImageView提供图像。

显然,这可能至少在我的设备上,尽管你的里程可能会有所不同。

在清单中,我们正常注册Widget的 ,并注册处理WebView及其图像捕获的服务。

  ...    ...          

在Widget的info文件widget_info.xml ,我将最小大小设置为4 x 2。

 < ?xml version="1.0" encoding="utf-8"?>  

对于此示例,Widget的布局widget_layout.xml只是一个ImageView.

  

此示例中的AppWidgetProvider仅覆盖onUpdate()方法,因为我们使用相同的ACTION_APPWIDGET_UPDATE来触发我们自己的AlarmManager更新。 请注意,只要有一个活动的Widget,示例警报将每30秒触发一次。 您可能不希望在测试之外执行此操作,因为Widget更新可能相当昂贵。

 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); } } 

Service ,我们实例化一个WebView ,并将其添加到FrameLayout ,而FrameLayout又被添加到WindowManager ,其宽度和高度参数为零。 然后我们在WebView加载测试URL,当页面完成时,我们强制WebView布局到适当的大小,并通过Canvas对象将其绘制到我们的目标Bitmap 。 这是在稍微延迟之后完成的,以允许WebView完全呈现自身,以免我们最终得到一个空白的白色图像。 然后在RemoteViews对象上设置Bitmap以更新Widget布局中的ImageView 。 我在代码中留下了Toast用于测试目的,因为我们的示例Widget可能比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((px < py ? py : px), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((px < py ? px : py), 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; } } 

这是Widgety善良的截图。

WebWidget截图

加上上面的答案,

对于收到此错误的人 – 无法添加窗口。 对于此窗口types的权限被拒绝 ,至少在我的情况下,运行marshmallow的设备需要更改types。

只需更换

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY

WindowManager.LayoutParams.TYPE_TOAST (或)

WindowManager.LayoutParams.TYPE_APPLICATION_PANEL

它会完美地运作。

注意:检查并确认Nexus6p运行最新版本的marsmallow。

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY需要权限android.permission.INTERNAL_SYSTEM_WINDOW ,只能添加到Android系统相关的应用程序。

对于想要使用Javascript解析数据的人来说,一旦页面完成加载onPageFinished(),也不要忘记更改Web视图的高度和宽度。

我完全忽略了上述答案中这一点的重要性,最终浪费了大量时间。

最初我的假设是因为我的要求是不通过图像视图将Web视图中的内容显示到窗口小部件,这不是必需的。

事实certificate,除非视图宽度和高度不为零,否则javascript无法解析Web视图中的数据。