H5 взаимодействует с родным приложением

JavaScript

предисловие

При разработке страниц H5 во внешнем интерфейсе часто есть страницы H5, которые необходимо встроить в приложение. Основная причина использования страниц H5 в APP заключается в том, что он работает в браузере, поэтому его нужно разработать только один раз, и он может отображаться в разных операционных системах, а итеративная версия очень удобна. Затраты на разработку относительно невелики.

В процессе разработки часто необходимо взаимодействовать с APP. В этой статье взаимодействие между двумя сторонами разобрано с точки зрения H5.Если это не является исчерпывающим, добро пожаловать на добавление исправлений.Взаимодействие примерно делится на эти две ситуации:

  • односторонняя связь
  • Не устраивает взаимодействие возврата и обратного вызова, необходимое для передачи одного параметра.

односторонняя связь

Односторонняя связь далее делится на связь, не требующую передачи параметров, и связь, требующую передачи параметров.

  1. Связь без параметров

    Ему просто нужно выполнить действие перехода между нативной страницей и страницей H5, и не нужно передавать данные друг другу:

    • Собственный переход к H5: просто отправьте URL-адрес, соответствующий H5, мобильным студентам.
    • H5 jump native: location.herf = имя протокола, соответствующее собственной странице, на которую нужно перейти
    示例:
    // H5
    window.location = 'app://login';
    
    // 原生(以IOS端为例)
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {  
      
      // 一般用作交互的链接都会有一个固定的协议头,这里我们一“app”作为协议头为了,实际项目中可以修改
      if ([scheme isEqualToString:@"app"]) { // scheme为“app”说明是做交互的链接
          if ([host isEqualToString:@"login"]) { // host为“login”对应的就是登录操作
              NSDictionary *paramsDict = [request.URL getURLParams];
              UIAlertView *alert = [[UIAlertView alloc] 
              [alert show];
          }
      return YES;
    }
    
  2. Связь, которая должна передавать параметры H5 и APP нуждаются в односторонней передаче данных.Вот два способа:

    • параметр URL:

    Переносите параметры за H5url или за протоколом приложения, а также перехватывайте и фильтруйте необходимые параметры для использования в соответствующих средах разработки.

    H5向原生传参示例:
    // H5
    window.location = 'app://login?account=13011112222&password=123456'; //将参数拼接到协议后面
    
    // 原生(以IOS端为例)
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {  
      NSString *scheme = request.URL.scheme;
      NSString *host = request.URL.host;
      
      // 一般用作交互的链接都会有一个固定的协议头,这里我们一“app”作为协议头为了,实际项目中可以修改
      if ([scheme isEqualToString:@"app"]) { // scheme为“app”说明是做交互的链接
          if ([host isEqualToString:@"login"]) { // host为“login”对应的就是登录操作
              NSDictionary *paramsDict = [request.URL getURLParams];
              NSString *account = paramsDict[@"account"];
              NSString *password = paramsDict[@"password"];
              NSString *msg = [NSString stringWithFormat:@"执行登录操作,账号为:%@,密码为:%@", account, password];
              UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"原生弹窗" message:msg delegate:nil cancelButtonTitle:@"好" otherButtonTitles:nil, nil];
              [alert show];
          }
      return YES;
    }
    
    • параметр окна:

    Поскольку приложение является хостом и может напрямую обращаться к h5, этот тип вызова относительно прост, т. е. предоставляет доступ к некоторым глобальным объектам (включая методы) в h5, а затем вызывает эти объекты в родном приложении.

    原生调用H5示例:
    // H5
    window.sdk= {
      double = value => value * 2
      trible = value => value * 3 
    } 
    
    // 原生(以IOS端为例)
    NSString *func = @"window.sdk.double(10)";
    NSString *str = [webview stringByEvaluatingJavaScriptFromString:func];// 20
    
    H5调用原生示例:
    // 原生(以IOS端为例)
    @interface AppSdk : NSObject
    {}
    - (int) double:(int)value;
    - (int) triple:(int)value;
    @end
    @implementation AppSdk
    - (int) double:(int)value {
      return value * 2;
    }
    - (int) triple:(int)value {
      return value * 3;
    }
    @end
    JSContext *context=[webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    AppSdk *appSdk = [AppSdk new];
    context[@"appSdk"] = appSdk;
    
    H5:
    
    window.appSdk.double(10); // 20
    

двусторонняя связь

Упомянутое выше взаимодействие односторонней связи обычно делает простой метод очень фрагментированным.В некоторых немного сложных сценариях стоимость обслуживания обоих концов очень высока, поэтому мы обычно чаще используем двустороннюю связь. Мы можем сделать много вещей в функции обратного вызова. Здесь же упомянем всем известный WebViewJavaScriptBridge:

  • Основы WebViewJavaScriptBridge
  • Подготовка WebViewJavaScriptBridge
  • WebViewJavaScriptBridge изначально вызывает H5
  • WebViewJavaScriptBridgeH5 вызывает родной

Фундаментальный

Основной принцип WebViewJavaScriptBridge заключается в том, чтобы просто построить мост, затем зарегистрироваться и вызвать других.

Зарегистрируйте метод OC в мосте и позвольте JS вызывать его.

Зарегистрируйте метод JS в мосте и позвольте OC вызывать его.

Готов к работе

  • js-инициализация:

    Вставьте следующие две функции в js

    function setupWebViewJavascriptBridge(callback) {
       if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
       if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
       window.WVJBCallbacks = [callback]; // 创建一个 WVJBCallbacks 全局属性数组,并将 callback 插入到数组中。
       var WVJBIframe = document.createElement('iframe'); // 创建一个 iframe 元素
       WVJBIframe.style.display = 'none'; // 不显示
       WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'; // 设置 iframe 的 src 属性
       document.documentElement.appendChild(WVJBIframe); // 把 iframe 添加到当前文导航上。
       setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
    }
    
    // 这里主要是注册 OC 将要调用的 JS 方法。下面具体的交互操作会提到
    setupWebViewJavascriptBridge(function(bridge){
      
    });
    

Нативный вызов на H5

Чтобы вызвать js H5 изначально, требуется два шага. Во-первых, js нужно внедрить метод a в мост. Вторым шагом, конечно же, является вызов метода a в мосте на нативной стороне.

  1. Метод внедрения js в мост

    Готовясь к работе выше, мы упомянули, что вторая функция в js — это регистрация JS-метода, который будет вызываться OC, Конкретные операции заключаются в следующем:

    // 往桥梁中注入js方法a
    setupWebViewJavascriptBridge(function(bridge){
       // 声明 OC 需要调用的 JS 方法。
       bridge.registerHanlder('a',function(data,responseCallback){
           // data 是 OC 传递过来的数据.
           // responseCallback 是调用完毕之后传递给 OC 的数据
           alert("JS 被 OC 调用了.");
           responseCallback({jsdata: "js 的数据",from : "JS"});
       })
    }); 
    });
    
  2. OC вызывает метод в мосте

    [_jsBridge callHandler:@"a" data:@"传递给 JS 的参数" responseCallback:^(id responseData) {
       NSLog(@"JS 的返回值: %@",responseData);
    }];
    

H5 вызывает родной

Нативный вызов H5 также состоит из двух шагов. Регистрируйтесь сами, звоните другим.

  1. Метод б введения ОК в мост

    [_jsBridge registerHandler:@"b" handler:^(id data, WVJBResponseCallback responseCallback) {
       // data 是 JS 传递过来的数据.
       // responseCallback 是调用完毕之后传递给 js 的数据
       responseCallback(@"传给js的值");
    }];
    
  2. JS вызывает метод b в мосте

    WebViewJavascriptBridge.callHandler('b',{data : "传给 OC 的入参"},function(dataFromOC){
           alert("JS 调用了 OC 的方法");
           alert('调用结束后OC返回给JS的数据:', dataFromOC);
    });
    

метод вызова

  1. Три способа настроить JS с помощью OC

        // 单纯的调用 JSFunction,不往 JS 传递参数,也不需要 JSFunction 的返回值。
        [_jsBridge callHandler:@"a"];
        // 调用 JSFunction,并向 JS 传递参数,但不需要 JSFunciton 的返回值。
        [_jsBridge callHandler:@"a" data:@"传给js的入参"];
        // 调用 JSFunction ,并向 JS 传递参数,也需要 JSFunction 的返回值。
        [_jsBridge callHandler:@"a" data:@"传递给 JS 的参数" responseCallback:^(id responseData) {
            NSLog(@"JS 的返回值: %@",responseData);
        }];
    
  2. Три способа настроить OC с помощью JS

         // JS 单纯的调用 OC 的 block
        WebViewJavascriptBridge.callHandler('b');
    
        // JS 调用 OC 的 block,并传递 JS 参数
        WebViewJavascriptBridge.callHandler('b',"JS 参数");
    
        // JS 调用 OC 的 block,传递 JS 参数,并接受 OC 的返回值。
        WebViewJavascriptBridge.callHandler('b',{data : "这是 JS 传递到 OC 的数据"},function(dataFromOC){
                alert("JS 调用了 OC 的方法!");
                document.getElementById("returnValue").value = dataFromOC;
        });
    

над.