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

虽然我明白一个App Widget不直接支持WebView ,是不是可以使用ImageView (这是支持的),还有一种像这里描述的为ImageView生成图像的技术? WebView不会直接使用,而只能在后台使用,以便为ImageView提供图像。

Solutions Collecting From Web of "Android:将WebView输出加载到App Widget中"

这显然是可能的,至less在我的设备上,虽然你的里程可能会有所不同。

在清单中,我们正常注册Widget的<receiver> ,并注册处理WebView及其图像捕获的Service

 <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的信息文件widget_info.xml ,我将最小大小设置为4 x 2。

 <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/widget_layout" android:minWidth="292dip" android:minHeight="146dip" /> 

对于这个示例,Widget的布局widget_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" /> 

AppWidgetProvider中的AppWidgetProvider仅覆盖onUpdate()方法,因为我们使用相同的ACTION_APPWIDGET_UPDATE来通过AlarmManager触发我们自己的更新。 请注意,只要有一个活动的小部件,示例警报就会每30秒触发一次。 您可能不想在testing之外进行此操作,因为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 ,然后将其添加到WindowManager ,其宽度和高度参数为零。 然后,我们在WebView加载一个testingURL,当页面结束时,我们强制WebView布局到合适的大小,并通过Canvas对象将其绘制到我们的目标Bitmap 。 这是稍微延迟后完成,以使WebView完全呈现自己,以免我们结束了一个空白,白色的图像。 然后, Bitmap被设置在RemoteViews对象上,以更新Widget布局中的ImageView 。 为了testing目的,我在代码中留下了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的权限被拒绝 ,至less在我的情况下,运行棉花糖的设备需要更改。

只需更换

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY为其中之一

WindowManager.LayoutParams.TYPE_TOAST (或)

WindowManager.LayoutParams.TYPE_APPLICATION_PANEL

它会工作得很好。

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

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

当页面在onPageFinished()上完成加载时,不要忘记更改Web视图的高度和宽度,以便使用Javascriptparsing数据。

我完全忽略了上述答案中的重要性,结果浪费了很多时间。

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

事实certificate,JavaScript不能parsing从Web视图的数据,除非视图的宽度和高度不为零。