Android: utilisation de WebView en dehors d'un contexte D'activité

J'essaie de réaliser un grattage Web à travers un IntentService d'arrière-plan qui gratte périodiquement un site Web sans afficher une vue sur le téléphone des utilisateurs.

  • Comme je dois appeler du javascript sur la page chargée, Je ne peux pas utiliser de HttpGet, etc.
  • je dois donc utiliser une instance WebView qui ne peut s'exécuter que sur un thread D'interface utilisateur.
  • toute tentative de démarrer une activité qui utilise un WebView entraîne une vue entrant au premier plan des téléphones (selon Android conception des activités)
  • toute tentative d'utilisation D'un WebView en dehors d'un contexte D'activité a entraîné une erreur indiquant que vous ne pouvez pas utiliser WebView sur un thread non-UI.
  • pour diverses raisons de complexité, Je ne peux pas envisager d'utiliser des bibliothèques telles que Rhino pour le raclage web sans interface utilisateur.

Est-il un moyen de contourner ce problème?

21
demandé sur Pierre 2013-09-18 10:11:11

8 réponses

Vous pouvez afficher une vue web à partir d'un service. Le Code ci-dessous crée une fenêtre à laquelle votre service a accès. La fenêtre n'est pas visible car la taille est 0 par 0.

public class ServiceWithWebView extends Service {

    @Override
    public void onCreate() {
        super.onCreate();

        WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        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.gravity = Gravity.TOP | Gravity.LEFT;
        params.x = 0;
        params.y = 0;
        params.width = 0;
        params.height = 0;

        LinearLayout view = new LinearLayout(this);
        view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));

        WebView wv = new WebView(this);
        wv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
        view.addView(wv);
        wv.loadUrl("http://google.com");

        windowManager.addView(view, params);
    }
}

Cela nécessitera également l'autorisation android.permission.SYSTEM_ALERT_WINDOW.

39
répondu Randy 2015-09-30 18:24:56

Corrigez - moi si je me trompe mais la bonne réponse à cette question Est qu'il n'y a aucun moyen possible d'utiliser un WebView en arrière-plan pendant que l'utilisateur fait d'autres choses sur le téléphone sans interrompre l'utilisateur au moyen d'une activité.

J'ai appliqué les suggestions de Randy et Code_Yoga: utiliser une activité avec " Thème.NoDisplay " pour lancer un service d'arrière-plan avec un WebView pour faire un peu de travail. Cependant même si aucune vue n'est visible le passage à cette activité pour cela deuxième pour démarrer les services interrompt l'utilisateur (ex. comme mettre en pause un jeu de course qui était joué).

Des nouvelles totalement désastreuses pour mon application, donc j'espère toujours que quelqu'un me donnera un moyen d'utiliser un WebView qui n'a pas besoin d'une activité (ou un substitut à un WebView qui peut accomplir la même chose)

9
répondu Pierre 2013-09-28 10:51:35

, Vous pouvez l'utiliser pour masquer l'Activité

         <activity android:name="MyActivity"
          android:label="@string/app_name"
          android:theme="@android:style/Theme.NoDisplay">

Cela empêchera l'application de montrer toute activité. Et puis vous pouvez faire vos affaires dans l'activité.

7
répondu Code_Yoga 2013-09-25 07:45:36

La solution était comme ça, mais avec Looper.getMainLooper ():

Https://github.com/JonasCz/save-for-offline/blob/master/app/src/main/java/jonas/tool/saveForOffline/ScreenshotService.java

@Override
public void onCreate() {
    super.onCreate();
    //HandlerThread thread = new HandlerThread("ScreenshotService", Process.THREAD_PRIORITY_BACKGROUND);
    //thread.start();
    //mServiceHandler = new ServiceHandler(thread.getLooper()); // not working
    mServiceHandler = new ServiceHandler(Looper.getMainLooper()); // working
}

, Avec l'aide de @JonasCz : https://stackoverflow.com/a/28234761/466363

2
répondu Shimon Doodkin 2017-05-23 12:10:21

Un WebView ne peut pas exister en dehors d'une activité ou D'un Fragment car il s'agit d'une interface utilisateur. Cependant, cela signifie qu'une activité est seulement nécessaire pour créer le WebView, pas gérer toutes ses demandes.

Si vous créez le WebView invisible dans votre activité principale et que vous l'avez accessible à partir d'un contexte statique, vous devriez être capable d'effectuer des tâches dans la vue en arrière-plan depuis n'importe où, car je crois que toutes les E / S de WebView sont effectuées de manière asynchrone.

Pour enlever le morceau de ce global accès, vous pouvez toujours lancer un Service avec une référence à la WebView pour faire le travail dont vous avez besoin.

1
répondu user2587659 2014-06-17 15:53:28

Ou un substitut à un WebView qui peut accomplir la même chose

0
répondu Nartus Team 2014-08-22 10:14:58

Je sais que ça fait un an et demi, mais je suis maintenant confronté au même problème. Je l'ai résolu finalement en exécutant mon code Javascript dans un moteur de nœud qui s'exécute dans mon application Android. Il s'appelle JXCore . Vous pouvez prendre un coup d'oeil. Aussi, jetez un oeil à cet exemple qui exécute Javascript sans WebView. Je voudrais vraiment savoir ce que vous avez fini par utiliser?

0
répondu oriharel 2016-02-20 13:16:44

Pourquoi ne pas créer un service Backend qui fait le raclage pour vous?

Et puis vous interrogez simplement les résultats d'un Webservice RESTful ou même utilisez un middleware de messagerie (par exemple ZeroMQ).

Peut-être plus élégant si cela correspond à votre cas d'utilisation: laissez le service de raclage envoyer vos messages Push App via GCM:)

0
répondu McOzD 2016-03-08 09:26:31