android webview imageview android-appwidget appwidgetprovider

Android: carga de la salida de WebView en el Widget de la aplicación



imageview android-appwidget (2)

Añadiendo a la respuesta anterior,

Para las personas que reciben este error: no se puede agregar la ventana. Permiso denegado para este tipo de ventana, al menos en mi caso con dispositivos que ejecutan Marshmallow, el tipo debe cambiarse.

Simplemente reemplazar

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY a cualquiera

WindowManager.LayoutParams.TYPE_TOAST (o)

WindowManager.LayoutParams.TYPE_APPLICATION_PANEL

y funcionará perfectamente bien.

Nota: Comprobado y confirmado con Nexus6p ejecutando la última versión de marsmallow.

El WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY requiere el permiso android.permission.INTERNAL_SYSTEM_WINDOW que se puede agregar solo para las aplicaciones relacionadas con el sistema Android.

Además, no olvide cambiar la altura y el ancho de la vista web una vez que la página haya terminado de cargarse en onPageFinished () para las personas que buscan analizar datos con Javascript.

Pasé por alto completamente la importancia de esto en la respuesta anterior y terminé perdiendo mucho tiempo.

Inicialmente, mi suposición era que mi requisito no era mostrar los contenidos en la vista web al widget a través de una vista de Imagen, esto no era necesario.

Resulta que JavaScript no puede analizar los datos de la vista web a menos que el ancho y el alto de la vista no sean cero.

Aunque aprecio que un Widget de aplicación no sea compatible con WebView directamente, ¿es posible utilizar un ImageView (que es compatible) y una técnica como la que se describe here para generar la imagen para ImageView ? El WebView no se usaría directamente, sino que solo se usaría en el fondo para proporcionar la imagen para el ImageView .


Esto es posible, al parecer, al menos en mi dispositivo, aunque su kilometraje puede variar.

En el manifiesto, registramos el <receiver> del Widget como normal, y también registramos nuestro Service que maneja el WebView y su captura de imágenes.

<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>

En el archivo de información del widget, widget_info.xml , he establecido el tamaño mínimo en 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" />

Para este ejemplo, el diseño del Widget, widget_layout.xml , es simplemente un 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" />

El AppWidgetProvider en este ejemplo está anulando solo el método onUpdate() , ya que estamos usando el mismo ACTION_APPWIDGET_UPDATE para activar nuestras propias actualizaciones con AlarmManager . Tenga en cuenta que la alarma de ejemplo se activará cada 30 segundos, siempre que haya un Widget activo. Probablemente no quiera hacer esto fuera de las pruebas, ya que las actualizaciones de Widget pueden ser bastante costosas.

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

En el Service , creamos una instancia de un WebView y lo agregamos a un FrameLayout , que a su vez se agrega al WindowManager con cero para sus parámetros de ancho y alto. Luego, cargamos una URL de prueba en la vista WebView , y cuando la página finaliza, WebView a la vista web para que WebView tamaño adecuado y la dibujamos en nuestro Bitmap objetivo a través de un objeto Canvas . Esto se hace después de un ligero retraso para permitir que WebView completamente, no sea que terminemos con una imagen en blanco y en blanco. El Bitmap se configura en un objeto RemoteViews para actualizar ImageView en el diseño del Widget. He dejado un Toast en el código para propósitos de prueba, ya que nuestro Widget de ejemplo puede actualizarse con más frecuencia que las actualizaciones de la página principal de .

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://.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; } }

Aquí hay una captura de pantalla de la bondad Widgety.