混合开发jsBridge介绍

H5与IOS 交互——WKWebView

OC调用JS

封装一个原生调用js的方法callJScallJS 为H5注入到window上的方法,供native调用实现js回调

/* 
 Evaluates the given JavaScript string.
 The completionHandler is passed the result of the script evaluation or an error.
 @param javaScriptString The JavaScript string to evaluate.
 @param completionHandler A block to invoke when script evaluation completes or fails.
*/
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;

//js回调
- (void)jsCallBackWith:(NSDictionary *)json
{
    NSLog(@"native-call-js:%@", json);
    // 防空
    if (!json || ![json isKindOfClass:[NSDictionary class]]) {
        return;
    }
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonstring = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    [self.webView evaluateJavaScript:[NSString stringWithFormat:@"callJS(%@);", jsonstring] completionHandler:^(id result, NSError * error) {
        NSLog(@"result==%@,error==%@",result,error);
    }];
}

JS调用OC

  1. iOS原生拦截URL, 这种方式从早期就存在,兼容性很好,但是由于是基于URL的方式,长度受到限制而且不太直观,数据格式有限制,而且建立请求有时间耗时。
  2. WKScriptMessageHandler 实现
    WKWebView 初始化时,有一个参数叫configuration,它是WKWebViewConfiguration类型的参数,而WKWebViewConfiguration的属性userContentController, 它又是WKUserContentController类型的参数。
    WKUserContentController对象有一个方法- addScriptMessageHandler:name:,以下定义了name为IOSBridge的MessageHandler
-(void)initWKWebView
{
    WKUserContentController* userContentController = [[WKUserContentController alloc] init];
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    configuration.userContentController = userContentController;
    configuration.preferences = [NSClassFromString(@"WKPreferences") new];
    configuration.preferences.javaScriptEnabled = true;
    // 默认是不能通过JS自动打开窗口的,必须通过用户交互才能打开
    configuration.preferences.javaScriptCanOpenWindowsAutomatically = false;
    configuration.allowsInlineMediaPlayback = YES; // 允许非全屏视频
    configuration.allowsPictureInPictureMediaPlayback = YES; // 画中画
    configuration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeAll;
    //js发送消息过来
    [configuration.userContentController addScriptMessageHandler:self name:@"IOSBridge"];
    WKWebView* webView = [[NSClassFromString(@"WKWebView") alloc] initWithFrame:self.bounds configuration:configuration];
    webView.UIDelegate = self;
    webView.navigationDelegate = self;
    webView.backgroundColor = [UIColor whiteColor];
    webView.opaque = NO;
    
    [webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    [webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
    //修改webview 的userAent
    [webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id __nullable userAgent, NSError * __nullable error) {
        NSString *language = [[MSALanguageManager manager] getLanguageFullName];//中文 zh-CN /日文 ja-JP / 英文 en-US
        NSString *hideNav = self.hideNativeNavigator ? @" isHiddenNativeNavigator" : @""; // 隐藏原生导航头
        NSString *customUserAgent = [userAgent stringByAppendingFormat:@" avalon %@ app/msa:%@", hideNav, language];
        webView.customUserAgent = customUserAgent;
        NSLog(@">>>>>当前webview UA:%@", customUserAgent);
    }];
    _realWebView = webView;
}
  1. H5端调用
window.webkit.messageHandlers.IOSBridge.postMessage({ method: 'getUserInfo', param: args });

H5与Android交互

待补充

H5对android和Ios两端的封装——jsBridge.js

(function(window) {
  window.NativeBridge = {}
  var ua = navigator.userAgent.toUpperCase()
  NativeBridge.IS_ANDROID = ua.indexOf('ANDROID') != -1 //当前环境是否为Android平台
  NativeBridge.IS_IOS = ua.indexOf('IPHONE') != -1 || ua.indexOf('IPAD') != -1 // 当前环境是否为IOS平台
  //--------------------------------------------------------
  //JS调用Native
  //--------------------------------------------------------
  NativeBridge.callNative = function(method) {
    var args = Array.prototype.slice.call(arguments, 1) //参数(非必填)
    var iosParam = { method: method, param: args }
    try {
      if (NativeBridge.IS_ANDROID) {
        console.log('call android native:', method, arguments)
        window.AndroidBridge.service.postMessage(iosParam)
      } else if (NativeBridge.IS_IOS) {
        console.log('call ios native:', method, arguments)
        window.webkit.messageHandlers.IOSBridge.postMessage(iosParam)
      } else {
        console.log('not in native:', method, arguments)
        throw new error('没有在移动环境')
      }
      return true
    } catch (e) {
      console.log('call native err:', e)
      if (method == 'toast' || method == 'alert') {
        alert(args[0])
      }
      return false
    }
  }
  //--------------------------------------------------------
  //Native调用JS
  //--------------------------------------------------------

  NativeBridge.nativeHandlerList = []

  NativeBridge.registerNativeListener = function(method, handler) {
    var has = false
    for (var i = 0; i < NativeBridge.nativeHandlerList.length; i++) {
      if (NativeBridge.nativeHandlerList[i].method == method && NativeBridge.nativeHandlerList[i].handler == handler) {
        //has = true;
        throw new Error('已经注册过同一个方法')
        //NativeBridge.nativeHandlerList[i].handler = handler;
      }
    }
    if (!has) {
      NativeBridge.nativeHandlerList.push({ method: method, handler: handler })
    }
  }

  NativeBridge.removeNativeListener = function(method) {
    for (var i = NativeBridge.nativeHandlerList.length - 1; i >= 0; i--) {
      if (NativeBridge.nativeHandlerList[i].method == method) {
        NativeBridge.nativeHandlerList.splice(i, 1)
      }
    }
  }
  callJS = function(data) {
    console.log('native call js src data:' + data)
    eval(data)
    console.log('native call js:' + data.method + ',参数:' + data.data)
    for (var i = 0; i < NativeBridge.nativeHandlerList.length; i++) {
      if (NativeBridge.nativeHandlerList[i].method == data.method) {
        NativeBridge.nativeHandlerList[i].handler(data.data)
      }
    }
  }
})(window)

使用

  1. 单页项目在index.html 文件引用以上nativeBridge.js

  2. JS调用Native

/**
* @params method方法名,string 类型
* @params param参数,任意类型
*/
window.NativeBridge.callNative('setNativeTitle', to.meta.title)
  1. Native调用JS
  mounted() {
    window.NativeBridge.registerNativeListener('notifyDataCallBack', data => {
      if (data) {
        console.log('notifyDataCallBack:mounted')
        // Toast('重新加载')
        this.getRes('')
      }
    })
  },
  beforeDestroy() {
    window.NativeBridge.removeNativeListener('notifyDataCallBack')
  }

开源的JSBridge

参考

H5与IOS 交互
深入浅出JSBridge:从原理到使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值