Lernen Sie den Funktionsmechanismus von jsBridge in einem Artikel kennen

Lernen Sie den Funktionsmechanismus von jsBridge in einem Artikel kennen

Die APP unseres Unternehmens ist eine typische hybride Entwicklungs-APP, die Front-End-Seiten einbettet. Um den gleichen Effekt wie die nativen Seiten zu erzielen, können die Front-End-Seiten nicht umhin, einige native Methoden aufzurufen. jsBridge ist die Brücke zwischen js und原生Kommunikation. Dieser Artikel spricht nicht über konzeptionelle Dinge, sondern analysiert den jsBridge Quellcode in unserem Projekt, um zu verstehen, wie er aus der Front-End-Perspektive implementiert wird.

js aufrufende Methode

Schauen wir uns an, wie js eine native Methode aufruft. Zuerst wird während der Initialisierung die Methode window.WebViewJavascriptBridge.init aufgerufen:

Fenster.WebViewJavascriptBridge.init()

Wenn Sie dann eine native Methode aufrufen möchten, können Sie die folgende Funktion verwenden:

Funktion native (Funktionsname, Argumente = {}, Rückruffunktion, Fehlerrückruffunktion) {
    // Überprüfen Sie, ob die Parameter gültig sind, wenn (args && typeof args === 'object' && Object.prototype.toString.call(args).toLowerCase() === '[object object]' && !args.length) {
        args = JSON.stringify(args);
    } anders {
        throw new Error('args entspricht nicht der Spezifikation');
    }
    // Feststellen ob es sich um eine Mobiltelefonumgebung handelt if (getIsMobile()) {
        //Rufen Sie die Methode callHandler des Objekts window.WebViewJavascriptBridge auf window.WebViewJavascriptBridge.callHandler(
            Funktionsname,
            Argumente,
            (res) => {
                res = JSON.parse(res);
                wenn (res.code === 0) {
                    gibt Rückruffunktion (res) zurück;
                } anders {
                    gibt errorCallbackFunc(res) zurück;
                }
            }
        );
    }
}

Geben Sie einfach den Methodennamen, die Parameter und den aufzurufenden Rückruf ein. Zuerst werden die Parameter überprüft und dann die Methode window.WebViewJavascriptBridge.callHandler aufgerufen.

Darüber hinaus können Rückrufe für native Aufrufe bereitgestellt werden:

Fenster.WebViewJavascriptBridge.registerHandler(funcName, callbackFunc);

Schauen wir uns als Nächstes an, was window.WebViewJavascriptBridge ist.

Android

Die Datei WebViewJavascriptBridge.js enthält eine selbstausführende Funktion, die zunächst einige Variablen definiert:

// Variable definieren var messagingIframe;
var sendMessageQueue = [];// Warteschlange zum Senden von Nachrichten var receiveMessageQueue = [];// Warteschlange zum Empfangen von Nachrichten var messageHandlers = {};// Nachrichtenhandler var CUSTOM_PROTOCOL_SCHEME = 'yy';// Benutzerdefiniertes Protokoll var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/';

var responseCallbacks = {}; // Antwort-Rückruf var uniqueId = 1;

Ich habe es einfach entsprechend dem Variablennamen übersetzt und die spezifische Verwendung wird als Nächstes analysiert. Als nächstes wird das WebViewJavascriptBridge -Objekt definiert:

var WebViewJavascriptBridge = Fenster.WebViewJavascriptBridge = {
    init: init,
    senden: senden,
    registerHandler: registerHandler,
    callHandler: callHandler,
    _fetchQueue: _fetchQueue,
    _handleMessageFromNative: _handleMessageFromNative
};

Sie können sehen, dass es sich um ein gewöhnliches Objekt handelt, an das einige Methoden angehängt sind. Ich werde mir die spezifischen Methoden jetzt nicht ansehen und weiter unten fortfahren:

var doc = Dokument;
_createQueueReadyIframe(doc);

Die Methode _createQueueReadyIframe wird aufgerufen:

Funktion _createQueueReadyIframe (Dokument) {
    MessagingIframe = doc.createElement('iframe');
    MessagingIframe.style.display = "keine";
    doc.documentElement.appendChild(messagingIframe);
}

Diese Methode ist sehr einfach. Erstellen Sie einfach ein verstecktes iframe , fügen Sie es in die Seite ein und fahren Sie fort:

// Erstellen Sie ein Ereignisobjekt vom Typ „Events“ (grundlegendes Ereignismodul). var readyEvent = doc.createEvent('Events');
// Definieren Sie den Ereignisnamen als WebViewJavascriptBridgeReady
readyEvent.initEvent('WebViewJavascriptBridgeReady');
//Lösen Sie das Ereignis durch documentdoc.dispatchEvent(readyEvent) aus.

Hier wird ein benutzerdefiniertes Ereignis definiert und direkt gesendet. Andere Stellen können auf dieses Ereignis genauso hören wie auf native Ereignisse:

document.addEventListener(
    "WebViewJavascriptBridgeReady",
    Funktion () {
        Konsole.log(Fenster.WebViewJavascriptBridge)
    },
    FALSCH
);

Der Zweck hier besteht meines Wissens darin, dass, wenn die jsBridge Datei nach anderem Code eingeführt wird, sichergestellt werden muss, dass der vorherige Code weiß, wann das window.WebViewJavascriptBridge -Objekt verfügbar ist. Wenn festgelegt ist, dass die jsBridge zuerst eingeführt werden muss, ist diese Verarbeitung nicht erforderlich.

Die selbstausführende Funktion endet hier. Als nächstes schauen wir uns die anfängliche init Methode an:

Funktion init (messageHandler) {
    wenn (WebViewJavascriptBridge._messageHandler) {
        throw new Error('WebViewJavascriptBridge.init zweimal aufgerufen');
    }
    // Beim Aufruf von init werden keine Parameter übergeben, daher messageHandler=undefined
    WebViewJavascriptBridge._messageHandler = NachrichtenHandler;
    // Derzeit ist „receiveMessageQueue“ nur ein leeres Array, var „receiveMessages“ = „receiveMessageQueue“;
    receiveMessageQueue = null;
    für (var i = 0; i < empfangeneNachrichten.Länge; i++) {
        _dispatchMessageFromNative(empfangeneNachrichten[i]);
    }
}

Aus Initialisierungsperspektive scheint diese init Methode nichts zu bewirken. Schauen wir uns als Nächstes callHandler an, um zu sehen, wie die Methode von Android aufgerufen wird:

Funktion CallHandler (HandlerName, Daten, AntwortCallback) {
    _doSend({
        handlerName: handlerName,
        Daten: Daten
    }, Antwortrückruf);
}

Nach der Verarbeitung der Parameter wird die Methode _doSend erneut aufgerufen:

Funktion _doSend (Nachricht, Antwort-Callback) {
    // Wenn ein Rückruf bereitgestellt wird if (responseCallback) {
        // Eine eindeutige Callback-ID generieren
        var callbackId = 'cb_' + (uniqueId++) + '_' + neues Date().getTime();
        // Der Rückruf wird im responseCallbacks-Objekt mit der ID responseCallbacks[callbackId] = responseCallback gespeichert.
        // Fügen Sie der an die native Nachricht zu sendenden Nachricht die Rückruf-ID hinzu message.callbackId = callbackId;
    }
    //Nachricht zur Nachrichtenwarteschlange hinzufügen sendMessageQueue.push(message);
    messagingIframe.src = BENUTZERDEFINIERTES PROTOKOLL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
}

Diese Methode generiert beim Aufruf der nativen Methode zunächst eine eindeutige id für die Rückruffunktion und speichert sie im eingangs definierten responseCallbacks -Objekt. Anschließend fügt sie die id den zu sendenden Informationen hinzu, sodass die Struktur einer message wie folgt aussieht:

{
    Handlername,
    Daten,
    Rückruf-ID
}

Fügen Sie dann die message dem am Anfang definierten sendMessageQueue Array hinzu und legen Sie schließlich src Attribut des iframe fest: yy://__QUEUE_MESSAGE__/ , was eigentlich eine benutzerdefinierte Protokoll- url ist. Ich habe eine einfache Suche durchgeführt und festgestellt, dass native diese url abfängt, um die entsprechende Verarbeitung durchzuführen. Wir können hier nicht weitermachen, da wir nicht wissen, was Native getan hat. Nach einer einfachen Suche habe ich diese Bibliothek gefunden: WebViewJavascriptBridge. Unser Unternehmen sollte sie auf Grundlage dieser Bibliothek geändert haben. Nachdem ich einige Artikel im Internet kombiniert habe, weiß ich ungefähr, dass Native, nachdem es diese url abfängt, die Methode window.WebViewJavascriptBridge._fetchQueue von js aufruft:

Funktion _fetchQueue () {
    // Konvertieren Sie die Nachrichtenwarteschlange, die wir senden möchten, in eine Zeichenfolge var messageQueueString = JSON.stringify(sendMessageQueue);
    // Nachrichtenwarteschlange löschen sendMessageQueue = [];
    // Android kann die zurückgegebenen Daten nicht direkt lesen und kommuniziert daher weiterhin über die Quelle des Iframes mit Java: messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);
}

Nachdem Android url abgefangen hat, weiß es, dass js eine Nachricht an Android gesendet hat, und ruft daher aktiv die Methode _fetchQueue von js auf, um die zuvor zur Warteschlange hinzugefügte Nachricht herauszunehmen. Da es die von js Methode zurückgegebenen Daten nicht direkt lesen kann, wird die formatierte Nachricht zur url hinzugefügt und erneut über iframe gesendet. Zu diesem Zeitpunkt fängt das Native die url yy://return/_fetchQueue/ ab, nimmt dann die nachfolgende Nachricht heraus, analysiert den Namen und die Parameter der nativen Methode, die ausgeführt werden sollen, und führt die entsprechende native Methode aus. Wenn die native Methode ausgeführt wird, ruft sie aktiv window.WebViewJavascriptBridge._handleMessageFromNative von js auf:

Funktion _handleMessageFromNative (messageJSON) {
    // Gemäß der Logik der vorherigen Init-Methode wissen wir, dass receiveMessageQueue auf null gesetzt wird, also gehen wir zum else-Zweig if (receiveMessageQueue) {
        : receiveMessageQueue.push(messageJSON);
    } anders {
        _dispatchMessageFromNative(messageJSON);
    }
}

Sehen Sie sich an, was die Methode _dispatchMessageFromNative macht:

Funktion _dispatchMessageFromNative (messageJSON) {
    setzeTimeout(Funktion () {
        // Die ursprünglich zurückgesendete Nachricht ist vom Typ String und wurde in JSON konvertiert.
        var Nachricht = JSON.parse(messageJSON);
        var Antwortrückruf;
        // Der Java-Aufruf ist abgeschlossen und die zurückgesendete Antwort-ID ist die Callback-ID, die wir zuvor gesendet haben.
        wenn (Nachricht.Antwort-ID) {
            // Holen Sie die mit der ID verknüpfte Rückrufmethode aus dem ResponseCallbacks-Objekt responseCallback = responseCallbacks[message.responseId];
            wenn (!responseCallback) {
                zurückkehren;
            }
            // Rückruf ausführen, js ruft die Android-Methode auf und empfängt erfolgreich die Nachricht responseCallback(message.responseData);
            lösche responseCallbacks[message.responseId];
        } anders {
            // ...
        }
    });
}

messageJSON ist die von der nativen Methode zurückgesendete Nachricht. Neben den relevanten Informationen, die nach der Ausführung der nativen Methode zurückgegeben werden, enthält sie auch callbackId wir ihr zuvor übergeben haben, sodass wir diese id verwenden können, um den zugehörigen Callback in responseCallbacks zu finden und auszuführen. Zu diesem Zeitpunkt endet der Prozess, bei dem js die native Methode aufruft. Es gibt jedoch offensichtlich einen Zweig in der Funktion, wenn id nicht existiert. Wofür wird er verwendet? Was wir zuvor eingeführt haben, sind alle js , die native Methoden aufrufen, aber natürlich kann Native auch direkt Nachrichten an js senden, wie z. B. das allgemeine Abfangen der Return-Tastenfunktion. Wenn Native auf das Return-Tastenereignis lauscht, sendet es aktiv Informationen, um dies der Front-End-Seite mitzuteilen, und die Seite kann die entsprechende Logik ausführen. Dieser else Zweig wird verwendet, um diese Situation zu handhaben:

Funktion _dispatchMessageFromNative (messageJSON) {
    setzeTimeout(Funktion () {
        wenn (Nachricht.Antwort-ID) {
            // ...
        } anders {
            // So wie die Nachricht, die wir an den Native senden, eine ID haben kann, kann auch die Nachricht, die der Native an uns sendet, eine ID haben, und der Native intern wird dieser ID auch einen Rückruf zuordnen, wenn (message.callbackId) {
                var callbackResponseId = Nachricht.callbackId;
                //Wenn das Frontend dem nativen Gerät antworten muss, sollte es die zuvor vom nativen Gerät gesendete ID enthalten, damit das native Gerät den entsprechenden Rückruf über die ID finden und ausführen kann. responseCallback = function (responseData) {
                    _doSend({
                        Antwort-ID: Rückruf-Antwort-ID,
                        Antwortdaten: Antwortdaten
                    });
                };
            }
            // Wir haben keinen Standard-_messageHandler festgelegt, daher ist er undefiniert
            var Handler = WebViewJavascriptBridge._messageHandler;
            // Die gesendete Nachricht enthält nativ den Namen der Verarbeitungsmethode if (message.handlerName) {
                // Über den Methodennamen ermitteln, ob im messageHandlers-Objekt eine entsprechende Verarbeitungsmethode vorhanden ist handler = messageHandlers[message.handlerName];
            }
            versuchen {
                //Führen Sie die Verarbeitungsmethode handler(message.data, responseCallback) aus.
            } Fang (Ausnahme) {
                if (Typ der Konsole !== 'undefiniert') {
                    console.log('WebViewJavascriptBridge: WARNUNG: JavaScript-Handler hat ausgelöst.', Meldung, Ausnahme);
                }
            }
        }
    });
}

Wenn wir beispielsweise das native Return-Tastenereignis abhören möchten, registrieren wir es zuerst über die Methode des window.WebViewJavascriptBridge -Objekts:

Fenster.WebViewJavascriptBridge.registerHandler('onBackPressed', () => {
    // Tu etwas...
})

registerHandler lautet wie folgt:

Funktion registerHandler (HandlerName, Handler) {
    messageHandlers[handlerName] = handler;
}

Es ist ganz einfach. Wir speichern den Ereignisnamen und die Methode, die wir überwachen möchten, im Objekt messageHandlers . Wenn der native Monitor dann das Ereignis „Return Key“ empfängt, sendet er eine Nachricht mit der folgenden Struktur:

{
    Handlername: „onBackPressed“
}

Auf diese Weise können wir die Funktion finden, die wir über handlerName registriert haben, und sie ausführen.

An diesem Punkt ist die Logik der gegenseitigen Aufrufe zwischen js und Native in der Android-Umgebung beendet. Zusammenfassend:

1.js ruft native

Generieren Sie eine eindeutige id , speichern Sie den Rückruf und id , fügen Sie dann die zu sendenden Informationen (mit der diesmal generierten eindeutigen ID) einer Warteschlange hinzu und senden Sie anschließend eine benutzerdefinierte Protokollanforderung über iframe . Rufen Sie nach dem nativen Abfangen eine Methode des js window.WebViewJavascriptBridge -Objekts auf, um die Warteschlangeninformationen abzurufen, analysieren Sie die Anforderung und die Parameter und führen Sie die entsprechende native Methode aus. Übergeben Sie dann die Antwort (mit der vom Front-End gesendeten ID) an das Front-End, indem Sie die angegebene Methode von js window.WebViewJavascriptBridge aufrufen. Das Front-End findet dann den zuvor gespeicherten Rückruf über id und führt ihn aus.

2. Nativer Aufruf von js

Zuerst muss das Frontend die zu überwachenden Ereignisse im Voraus registrieren, den Ereignisnamen und den Rückruf speichern, und dann ruft der Native zu einem bestimmten Zeitpunkt die angegebene Methode js window.WebViewJavascriptBridge -Objekts auf. Das Frontend findet den registrierten Rückruf entsprechend dem Ereignisnamen des Rückgabeparameters zur Ausführung. Gleichzeitig übergibt der Native auch eine id . Wenn das Frontend nach der Ausführung der entsprechenden Logik eine Nachricht an den Native senden muss, muss die id zurückgebracht werden, und der Native findet den entsprechenden Rückruf zur Ausführung basierend auf der id .

Wie Sie sehen, ist die Logik sowohl auf js als auch auf der nativen Seite konsistent.

ios

ios und Android sind im Grunde gleich, es gibt jedoch einige Unterschiede in Details. Zunächst einmal sind die Protokolle unterschiedlich. ios Protokoll sieht folgendermaßen aus:

var CUSTOM_PROTOCOL_SCHEME_IOS = "https";
var QUEUE_HAS_MESSAGE_IOS = '__wvjb_queue_message__';

Wenn ios dann initialisiert und iframe erstellt, sendet es eine Anfrage:

var BRIDGE_LOADED_IOS = "__bridge_loaded__";
Funktion _createQueueReadyIframe (Dokument) {
    MessagingIframe = doc.createElement('iframe');
    MessagingIframe.style.display = "keine";
    wenn (istIphone()) {
        // Dies sollte die Brücke sein, die iOS zuerst laden muss
        messagingIframe.src = CUSTOM_PROTOCOL_SCHEME_IOS + '://' + BRIDGE_LOADED_IOS;
    }
    doc.documentElement.appendChild(messagingIframe);
}

Wenn ios dann unsere Nachrichtenwarteschlange erhält, muss es nicht durch iframe gehen. Es kann die zurückgegebenen Daten direkt abrufen, indem es die js -Funktion ausführt:

Funktion _fetchQueue () {
    var messageQueueString = JSON.stringify(sendMessageQueue);
    sendMessageQueue = [];
    return messageQueueString; // Direkt zurückkehren, ohne über Iframe zu gehen
}

Alles andere ist gleich.

Zusammenfassen

Dieser Artikel analysiert den Quellcode von jsBridge und stellt fest, dass es sich eigentlich um eine sehr einfache Sache handelt. Normalerweise haben Sie sich jedoch möglicherweise nicht ernsthaft damit befasst. Sie möchten immer etwas „Großes“ tun, also werden Sie zu einer „hochgesinnten“ Person. Ich hoffe, Sie werden nicht wie ich sein.

Dies ist das Ende dieses Artikels über das Erlernen des Betriebsmechanismus von jsBridge in einem Artikel. Weitere relevante Inhalte zum Betriebsmechanismus von jsBridge finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder durchsuchen Sie die folgenden verwandten Artikel weiter. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Detaillierte Erläuterung des JavaScript-Betriebsmechanismus und eine kurze Diskussion über Event Loop
  • Lassen Sie sich das Funktionsprinzip von JavaScript erklären
  • Detaillierter Prozess zur Installation von Docker, zum Erstellen von Images, zum Laden und Ausführen von NodeJS-Programmen
  • So führen Sie JavaScript in Jupyter Notebook aus
  • Lösen Sie das Problem, dass das Ausführen von JS-Dateien im Knotenterminal die ES6-Syntax nicht unterstützt
  • Tutorial zum Kompilieren und Ausführen von HTML-, CSS- und JS-Dateien in Visual Studio Code
  • Beispiel für die Ausführung von JavaScript mit Golang
  • Front-End-JavaScript-Funktionsprinzip

<<:  Detaillierte Erläuterung des tatsächlichen Prozesses der Master-Slave-Synchronisierung der MySQL-Datenbank

>>:  Zusammenfassung gängiger Befehle für den Einstieg in die MySQL-Datenbankgrundlagen

Artikel empfehlen

React-Beispiel zum Abrufen des Werts aus dem Eingabefeld

Reagieren Sie auf mehrere Arten, um den Wert des ...

So verwenden Sie allgemeine MySQL-Funktionen zur Verarbeitung von JSON

Offizielle Dokumentation: JSON-Funktionen Name Be...

So verwenden Sie Docker zum Erstellen eines privaten pypi-Repositorys

1. Konstruktion 1. Bereiten Sie die Datei htpassw...

Was bedeutet Eingabetyp und wie kann die Eingabe begrenzt werden?

Gängige Methoden zur Begrenzung der Eingabe 1. Um ...

Verwenden Sie reines CSS, um das A-Tag in HTML ohne JavaScript zu deaktivieren

Tatsächlich ist dieses Problem bereits aufgetreten...

Kompilieren Sie CPP-Dateien mit G++ in Ubuntu

Als ich die CPP-Datei zum ersten Mal mit G++ komp...

So implementieren Sie ein Glücksradspiel im WeChat-Applet

Ich stelle hauptsächlich vor, wie man im WeChat-A...

Mit CSS3 erstellter Hintergrundverlaufsanimationseffekt

Ergebnisse erzielen Implementierungscode html <...

So erstellen Sie einen MySQL PXC-Cluster

Inhaltsverzeichnis 1. Einführung in PXC 1.1 Einfü...

Zusammenfassung der Situationen, in denen MySQL-Indizes nicht verwendet werden

Indextypen in MySQL Im Allgemeinen können sie in ...

Vier praktische Tipps für JavaScript-String-Operationen

Inhaltsverzeichnis Vorwort 1. Eine Zeichenfolge t...

Einführung in die neuen Funktionen von MySQL 8.0.11

MySQL 8.0 für Windows v8.0.11 offizielle kostenlo...

Vue3 implementiert CSS unendlichen nahtlosen Scrolleffekt

In diesem Artikelbeispiel wird der spezifische Co...

So beheben Sie den abnormalen Fehler ERROR: 2002 in MySQL

Kürzlich ist beim Starten von MySQL ein Fehler au...

Docker verwendet Supervisor zur Verwaltung von Prozessvorgängen

Ein Docker-Container startet beim Start beispiels...