[JAVA] Je n'hésiterai plus! Personnaliser le plug-in Cordova / Monaca --- Essayez de réparer le plug-in InAppBrowser

Aperçu

Dans Monaca / Cordova, vous pouvez utiliser divers plug-ins, mais lors du développement d'une application, il y a des cas où le plug-in standard ne suffit pas. Dans un tel cas, il est possible de modifier le plug-in et d'ajouter les fonctions nécessaires, mais c'est souvent difficile car il n'y a pas beaucoup d'informations complètes. Par conséquent, à titre d'exemple de réparation de plug-in, je vais vous présenter comment ajouter des fonctions à InAppBrowser.

Pour essayer le contenu de cet article, vous avez besoin d'un environnement pour exécuter Cordova localement. De plus, étant donné que le code natif sera modifié, Xcode est requis pour iOS et Android Studio est requis pour Android.

(Bien que ce soit très difficile, vous pouvez également l'essayer en intégrant le plug-in cordova-plugin-inappbrowser sous forme de fichier zip en utilisant le plan Pro de Monaca, etc. et en modifiant le code dans le plug-in sur Monaca IDE. )

Quel genre de rénovation?

L'autre jour, M. Teratail voulait faire un processus qui "seule une URL spécifique ne bouge pas comme elle est", alors pensons à cela comme un thème. (JavaScript - Je veux empêcher "ne pas bouger tel quel" pour une URL spécifique dans Monaca InApp Browser (104255) | teratail)

En tant que condition, un modèle d'URL est défini à l'avance avec une expression régulière, et la page ne passe pas à la destination du lien uniquement lorsque l'expression régulière est mise en correspondance. De plus, lorsque cette fonction est activée, l'événement de déchargement sera déclenché afin qu'il puisse être acquis du côté JS.

Comme je le présenterai plus tard, cette modification est disponible sur https://github.com/knight9999/cordova-plugin-inappbrowser/tree/unload_list, donc si vous souhaitez l'utiliser immédiatement, veuillez l'essayer. regarde s'il te plait.

Exemple concret

Avec cette modification, les cas de test suivants peuvent être utilisés.

  1. Définissez " https: \ / \ / github \ .com \ / apache \ / cordova-plugin-inappbrowser \ / blob \ / master \ / README \ .md "comme un modèle d'URL qui interdit les transitions de page. .. (Je ne peux pas lire README.md)
  2. Dans InAppBrowser, ouvrez https://github.com/apache/cordova-plugin-inappbrowser
  3. Je ne peux pas passer à une page même si je clique sur le lien vers README.md
  4. L'événement de déchargement se déclenche

Par programme, cela ressemblera à ceci:

  document.getElementById('btn').addEventListener('click', function() {
    var ref = cordova.InAppBrowser.open('https://github.com/apache/cordova-plugin-inappbrowser', '_blank', 'location=yes', null, ['https:\/\/github\.com\/apache\/cordova-plugin-inappbrowser\/blob\/master\/README\.md']);
    ref.addEventListener('unload', function(json) { alert( json.url ); } );
  },false);

Vous permet de mettre une liste d'expressions régulières dans le cinquième paramètre de cordova.InAppBrowser.open. S'il correspond à cette expression canonique, il ne chargera pas la page et déclenchera à la place l'événement de déchargement.

Créer une application de travail

Étant donné que le plug-in ne fonctionne pas uniquement avec le plug-in, créez une application de travail, intégrez-y le plug-in et développez-le.

Tout d'abord, récupérez le navigateur d'application cordova-plugin-in depuis github. Dans un répertoire de votre choix, procédez comme suit:

$ git clone https://github.com/apache/cordova-plugin-inappbrowser.git
$ git checkout 1.6.1

Le répertoire cloné sera désormais [/ path / to / cordova-plugin-inappbrowser]. Nous le développerons sur la base de la version 1.6.1. (La version 1.7.x a actuellement un bogue dans UIWebView d'iOS, donc cet article est basé sur la série 1.6)

Ensuite, préparez une application fonctionnelle qui utilise ce plug-in. Créez un autre répertoire et procédez comme suit:

$ cordova create sample
$ cd sample
$ cordova platform add [email protected]
$ cordova platform add [email protected]

Ici, cordova cli est 6.5.0. C'est la même chose que la dernière version de Monaca aujourd'hui. De plus, la version de la plate-forme iOS est 4.4.0 et la version de la plate-forme Android est 6.2.3 afin de correspondre à la dernière version de Monaca.

Et puis, installez le navigateur d'application cordova-plugin-in que vous avez cloné précédemment.

$ cordova plugin add [/path/to/cordova-plugin-inappbrowser]

Vous disposez maintenant d'un environnement de développement. Après cela, travaillez dans ce répertoire d'applications de travail.

Contrôle de fonctionnement

Commençons par vérifier le fonctionnement. Soit iOS ou Android, c'est bien, mais ici, je vais l'essayer sur iOS.

Ouvrez le fichier www / index.html et ajoutez la balise button comme suit:

Avant correction

        <div class="app">
            <h1>Apache Cordova</h1>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Device is Ready</p>
            </div>
        </div>

modifié

        <div class="app">
            <h1>Apache Cordova</h1>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Device is Ready</p>
            </div>
            <button id="btn">Go Btn</button>
        </div>

Ensuite, dans js / index.js, enregistrez l'opération lorsque btn est tapé comme suit.

Avant correction

    onDeviceReady: function() {
        this.receivedEvent('deviceready');
    },

modifié

    onDeviceReady: function() {
        this.receivedEvent('deviceready');
        document.getElementById('btn').addEventListener('click', function() {
          var ref = cordova.InAppBrowser.open('https://github.com/apache/cordova-plugin-inappbrowser', '_blank', 'location=yes');
        },false);
    },

Comme il s'agit toujours d'un InAppBrowser normal, je n'ai pas défini le 5ème argument de la méthode ouverte.

$ cordova prepare ios

Après cela, ouvrez le projet avec Xcode et vérifiez le fonctionnement sur la machine réelle.

$ open platforms/ios/HelloCordova.xcworkspace

Lorsque l'écran HelloCorodva apparaît, avez-vous appuyé sur le bouton btn en dessous pour voir la page du navigateur d'application github cordova-plugin-in?

Réparation de la partie JavaScript

Après avoir confirmé l'opération, en tant que modification du plug-in InAppBrowser, modifiez d'abord la partie JavaScript. La partie JavaScript est commune à Android et iOS, mais nous allons d'abord nous concentrer sur iOS et le modifier. Parce que lors de la modification d'un plug-in, le test de fonctionnement est répété plusieurs fois, il est donc plus efficace de travailler sur ce que vous utilisez sur iOS, de le vérifier et, lorsqu'il est terminé, de donner un retour à la source du plug-in. Parce que c'est bon. (Je pense que oui, mais cela peut être différent pour certaines personnes)

L'endroit à réparer est généralement /plugins/cordova-plugins-inappbrowser/www/inappbrowser.js, mais en fait c'est juste celui qui a été installé lorsque le plug a été ajouté, donc c'est Je ne vais pas le réparer.

En outre, ce qui fonctionne réellement dans Xcode, ce sont les plates-formes / ios / www / plugins / cordova-plugins-inappbrowser / www / inappbrowser.js, mais même si vous réécrivez ceci, il sera basé sur chaque fois que vous préparez cordova. Je ne réglerai pas cela non plus, car il reviendra.

Le javascript à modifier pendant le développement de plug est platform / ios / platform_www / plugins / cordova-plugin-inappbrowser / www / inappbrowser.js. Si vous modifiez cela, chaque fois que vous préparez cordova, il sera copié sur les plates-formes / ios / www / plugins / cordova-plugins-inappbrowser / www / inappbrowser.js fonctionnant sous Xcode.

Modifions cela comme suit.

Changer avant:

    function InAppBrowser() {
       this.channels = {
            'loadstart': channel.create('loadstart'),
            'loadstop' : channel.create('loadstop'),
            'loaderror' : channel.create('loaderror'),
            'exit' : channel.create('exit')
       };
    }

Après le changement:

    function InAppBrowser() {
       this.channels = {
            'loadstart': channel.create('loadstart'),
            'loadstop' : channel.create('loadstop'),
            'loaderror' : channel.create('loaderror'),
            'unload' : channel.create('unload'),
            'exit' : channel.create('exit')
       };
    }

Ajout d'un déchargement sur le canal.

Puis changez-le comme suit.

Avant correction

    module.exports = function(strUrl, strWindowName, strWindowFeatures, callbacks) {
        // Don't catch calls that write to existing frames (e.g. named iframes).
        if (window.frames && window.frames[strWindowName]) {
            var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
            return origOpenFunc.apply(window, arguments);
        }

        strUrl = urlutil.makeAbsolute(strUrl);
        var iab = new InAppBrowser();

        callbacks = callbacks || {};
        for (var callbackName in callbacks) {
            iab.addEventListener(callbackName, callbacks[callbackName]);
        }

        var cb = function(eventname) {
           iab._eventHandler(eventname);
        };

        strWindowFeatures = strWindowFeatures || "";

        exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
        return iab;
    };

modifié

    module.exports = function(strUrl, strWindowName, strWindowFeatures, callbacks, ignoreList) {
        // Don't catch calls that write to existing frames (e.g. named iframes).
        if (window.frames && window.frames[strWindowName]) {
            var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
            return origOpenFunc.apply(window, arguments);
        }

        strUrl = urlutil.makeAbsolute(strUrl);
        var iab = new InAppBrowser();

        callbacks = callbacks || {};
        for (var callbackName in callbacks) {
            iab.addEventListener(callbackName, callbacks[callbackName]);
        }

        ignoreList = ignoreList || [];

        var cb = function(eventname) {
           iab._eventHandler(eventname);
        };

        strWindowFeatures = strWindowFeatures || "";

        exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures, ignoreList]);
        return iab;
    };

Changé pour recevoir ignoreList comme cinquième paramètre de fonction. Et s'il est vide, il est ajouté en tant que tableau vide à la fin du cinquième argument au moment de exec.

Ceci termine la modification de la partie JavaScript.

Correction d'Objective-C

Ensuite, modifions Objective-C. Le fichier cible est le fichier platform / ios / HelloCordova / Plugins / cordova-plugin-inappbrowser / CDVInAppBrowser.m. Ouvrez-le dans un Xcode assisté au lieu d'un éditeur de texte et corrigez-le.

Tout d'abord, préparez _unloadList en tant que variable d'instance. Cette variable contient une liste d'expressions régulières envoyées en JavaScript.

Avant correction

 @interface CDVInAppBrowser () {
     NSInteger _previousStatusBarStyle;
 }

modifié

 @interface CDVInAppBrowser () {
     NSInteger _previousStatusBarStyle;
     NSArray<NSString *> *_unloadList;
 }

Ensuite, dans la méthode open, stockez la liste des expressions régulières transmises depuis JavaScript dans _unloadList.

Avant correction

- (void)open:(CDVInvokedUrlCommand*)command
{
    CDVPluginResult* pluginResult;

    NSString* url = [command argumentAtIndex:0];
    NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf];
    NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]];

modifié

- (void)open:(CDVInvokedUrlCommand*)command
{
    CDVPluginResult* pluginResult;

    NSString* url = [command argumentAtIndex:0];
    NSString* target = [command argumentAtIndex:1 withDefault:kInAppBrowserTargetSelf];
    NSString* options = [command argumentAtIndex:2 withDefault:@"" andClass:[NSString class]];
    _unloadList = [command argumentAtIndex:3 withDefault:@[] andClass:[NSArray<NSString *> class]];

Ensuite, évaluons si l'URL spécifiée au moment de la transition de page correspond à _unloadList, et si elle correspond, arrêtez la transition de page et déclenchez l'événement de déchargement. Cela peut être implémenté à l'aide de la méthode webView: shouldStartLoadWithRequest: navigationType:. Si cette méthode renvoie OUI, la transition de page sera possible, et si NON est renvoyé, la transition de page ne se produira pas.

Modifiez la fin de cette méthode comme suit:

Avant correction

return YES;

modifié

    __block BOOL unloadFlag = NO;
    NSString *urlStr = [url absoluteString];
    [_unloadList enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        NSError *error = nil;
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:obj
                                                          options:NSRegularExpressionCaseInsensitive
                                                            error:&error];
        if (! error) {
            NSTextCheckingResult *match = [regex firstMatchInString:urlStr
                                                            options:0
                                                          range:NSMakeRange(0, urlStr.length)];
            if (match) {
                unloadFlag = YES;
            }
        }
    }];
    if (unloadFlag) {
        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                                                      messageAsDictionary:@{@"type":@"unload", @"url":urlStr}];
        [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
        
        [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
        return NO;
    }

    return YES;

C'est tout ce qu'on peut en dire. Le spécificateur __block est inclus car cette variable est (éventuellement) modifiée à partir de la syntaxe du bloc.

Contrôle de fonctionnement

Changeons le côté de l'application pour utiliser le nouveau InAppBrowser

Modifiez www / index.js comme suit:

    onDeviceReady: function() {
        this.receivedEvent('deviceready');
        document.getElementById('btn').addEventListener('click', function() {
          var ref = cordova.InAppBrowser.open('https://github.com/apache/cordova-plugin-inappbrowser', '_blank', 'location=yes', null, ['https:\/\/github\.com\/apache\/cordova-plugin-inappbrowser\/blob\/master\/README\.md']);
          ref.addEventListener('unload', function(json) { alert( json.url ); } );
        },false);
    },

Maintenant, README.md spécifié par le 5ème argument de la méthode open ne peut pas être ouvert, et l'événement de déchargement sera déclenché à ce moment.

Commentaires sur le plug-in

Les deux fichiers suivants ont été modifiés dans l'application de travail cette fois.

platforms/ios/platform_www/plugins/cordova-plugin-inappbrowser/www/inappbrowser.js platforms/ios/HelloCordova/Plugins/cordova-plugin-inappbrowser/CDVInAppBrowser.m

Ces deux modifications doivent être reflétées dans le plug-in InAppBrowser. Dans le répertoire du plug-in InAppBroweser, ce qui précède correspond à:

www/inappbrowser.js src/iOS/CDVInAppBrowser.m

Pour le dire simplement, je pense qu'il est normal de l'écraser entièrement, mais vous ne pouvez pas écraser inappbrowser.js.

platforms/ios/platform_www/plugins/cordova-plugin-inappbrowser/www/inappbrowser.js Quand j'ouvre

cordova.define("cordova-plugin-inappbrowser.inappbrowser", function(require, exports, module) {
 //Contenu du code
});

Cependant, veuillez remplacer uniquement ce "contenu du code" sous la forme www / inappbrowser.js. En d'autres termes, les plates-formes d'application de développement / ios / platform_www / plugins / cordova-plugin-inappbrowser / www / inappbrowser.js Le plug-in cordova-plugin-inappbrowser www / inappbrowser.js est celui sans la première et la dernière ligne de.

Pour CDVInAppBrowser.m, vous pouvez écraser et copier tel quel.

Résumé à ce jour

La version modifiée est https://github.com/knight9999/cordova-plugin-inappbrowser/tree/unload_list.

Prise en charge d'Android

Pour les applications de développement, supprimez le cordova-plugin-inappbrowser déjà intégré et réinstallez le cordova-plugin-inappbrowser collecté.

$ cordova plugin rm cordova-plugin-inappbrowser
$ cordova plugin add [/path/to/cordova-plugin-inappbrowser]

Désormais, le JavaScript modifié est également reflété du côté Android. Consultez plates-formes / android / platform_www / plugins / cordova-plugin-inappbrowser / www / inappbrowser.js.

Et préparez-vous une fois.

$ cordova prepare android

À propos d'Android Studio

Je ne pense pas que Cordova-Android 6.2.3 puisse être construit avec succès avec la dernière version d'Android Studio 3.0. Dans ce cas, veuillez télécharger et décompresser gradle-3.2-all.zip à partir de https://services.gradle.org/distributions/ afin de pouvoir l'utiliser depuis Android Studio. (Sur un Mac, il sera placé sous / Application / Android Studio.app/Contents/gradle)

Si vous obtenez une erreur EACCESS avec cordova compile etc., utilisez la commande -d pour afficher les détails de l'erreur et la traiter.

$ cordova compile android -d

De plus, lorsque vous l'ouvrez dans Android Studio, si vous recevez un message pour rétrograder, veuillez rétrograder.

Modification du code Java

Ensuite, ouvrez le répertoire plates-formes / android dans Android Studio. Lancez Android Studio et ouvrez le répertoire platform / android avec le Ouvrir un projet Android Studio existant.

Le fichier cible à modifier est platform / android / src / org / apache / cordova / inappbrowser / InAppBrowser.java.

Tout d'abord, je veux utiliser JSONArray, donc je vais l'importer.

modifié

import org.json.JSONArray;

Ensuite, immédiatement après la déclaration de classe d'InAppBrowser, définissez unloadList comme variable d'instance comme suit.

Avant correction

    private boolean shouldPauseInAppBrowser = false;
    private boolean useWideViewPort = true;

modifié

    private boolean shouldPauseInAppBrowser = false;
    private boolean useWideViewPort = true;
    private JSONArray unloadList;

Ensuite, lorsqu'il est appelé par la méthode open à partir de JavaScript, le tableau affecté par le 5ème argument est stocké dans JSONArray. Modifiez l'intérieur de la méthode d'exécution de la classe InAppBrowser.

Avant correction

            final String target = t;
            final HashMap<String, Boolean> features = parseFeature(args.optString(2));

modifié

            final String target = t;
            final HashMap<String, Boolean> features = parseFeature(args.optString(2));
            unloadList = args.optJSONArray(3);

Et enfin, modifiez la méthode shouldOverrideUrlLoading de la classe InAppBrowserClient (située dans le fichier InAppBrowser.java). Ici, s'il correspond à l'expression régulière, il renvoie un événement de déchargement pour empêcher les transitions de page. Ajoutez un processus de jugement à la fin de cette méthode.

Avant correction

            return false;

modifié

            boolean unloadFlag = false;
            for (int i=0;i<unloadList.length();i++) {
                String regex = unloadList.optString(i);
                if (url.matches(regex)) {
                    unloadFlag = true;
                }
            }
            if (unloadFlag) {
                try {
                    JSONObject obj = new JSONObject();
                    obj.put("type", "unload");
                    obj.put("url", url);
                    sendUpdate(obj, true);
                } catch (JSONException ex) {
                    LOG.e(LOG_TAG, "URI passed in has caused a JSON error.");
                }
                return true;
            }

            return false;

C'est similaire à webView: shouldStartLoadWithRequest: navigationType: sur iOS, mais notez que la valeur booléenne retournée par shouldOverrideUrlLoading sur Android est inversée. C'est une méthode avec des fonctionnalités similaires, mais elle n'est pas compatible avec iOS et Android. C'est une fonction différente de chaque cadre.

Ceci est complet.

Comme avec iOS, afin de refléter cela dans le plug-in, cette application de développement

platforms/android/src/org/apache/cordova/inappbrowser/InAppBrowser.java

Cordova-plugin-inappbrowser dans le répertoire plugin

src/android/InAppBrowser.java

Veuillez écraser.

Résumé à ce jour

Le correctif Android est également reflété dans https://github.com/knight9999/cordova-plugin-inappbrowser/tree/unload_list. De plus, la version du plug-in est 1.6.1-unload.

Résumé

En utilisant InAppBrowser comme thème, j'ai présenté comment modifier le plug-in Cordova / Monaca.

Le travail de développement / modification de plug-in nécessite la connaissance du code natif tel que Java et Objecitve-C, la connaissance du framework Cocoa et du framework Android, ainsi que du mécanisme CordovaLib, du mécanisme de fichier de configuration du plug-in cordova et des hooks. C'est une tâche difficile car il existe diverses exigences telles que la connaissance des scripts. (Pour les scripts de hook, j'ai écrit un article à https://qiita.com/KNaito/items/65587f5d51974e8b4adf, veuillez donc vous y référer également.)

Cependant, le développement de plug-ins élargira vos horizons et vous donnera une idée de la manière de décomposer les fonctionnalités de votre application. De plus, le plug-in peut être réutilisé et sera un atout pour le développement futur de l'application, alors essayez-le.

Recommended Posts

Je n'hésiterai plus! Personnaliser le plug-in Cordova / Monaca --- Essayez de réparer le plug-in InAppBrowser
Je n'hésiterai plus! Flux d'introduction RSpec