美文网首页
Weex开发:页面间通信方式

Weex开发:页面间通信方式

作者: 啧啧同学 | 来源:发表于2018-12-19 21:37 被阅读0次

    Weex超多大坑,最好别用

    白菜普及

    Weex 基于当代先进的 Web 开发技术,使用同一套代码来构建 Android、iOS 和 Web 应用。
    Weex 的结构是解耦的,渲染引擎与语法层是分开的,也不依赖任何特定的前端框架,目前主要支持 Vue.js 和 Rax 这两个前端框架。Weex 的另一个主要目标是跟进当代先进的 Web 开发和原生开发的技术,使生产力和性能共存。在开发 Weex 页面就像开发普通网页一样;在渲染 Weex 页面时和渲染原生页面一样。

    Weex与Native页面之间的通信主要是用module和globalEvent来实现,其中globalEvent可以为通过vue交互来与weex进行通信

    一. globalEvent:

    globalEvent 用于监听持久性事件,全局事件是需要额外 APIs 处理的次要 API。通过 addEventListener 注册事件监听,当你不再需要的时候,也可以通过 removeEventListener 取消事件监听。

    Native端

    let testDic = ["key" : "native主动发起广播至weex"]  
     weexInstance.fireGlobalEvent("NativeGlobalEvent", params: testDic)
    

    Vue.js

    
    const globalEvent = weex.requireModule('globalEvent')
    export default {
      methods: {
        ......省略N多代码
        addGlobalObserver() {
          globalEvent.addEventListener("NativeGlobalEvent", function (e) {
            modal.alert({
              message: e.key,
            });
          })
        },
        removeGlobalObserver() {
          globalEvent.removeEventListener("NativeGlobalEvent")
        }
      }
    }
    

    坑:多次调用addEventListener方法后,无法覆盖回调(函数),会触发多次回调的执行。
    exp: Vue.js多次调用addEventListener方法(比如5次),当Native的Weex实例发起fireGlobalEvent时,会直接执行5次函数体的 内的代码块;再此基础上手动调用3次,在native端再进行一次fireGlobalEvent操作,则会累积执行8次函数体内的代码块!但是如果调用removeEventListener,则会把这“八份回调”全部清除。
    所以实现通知时候需要额外处理相关的代码逻辑

    二.注册Module和callback回调

    Native端

    • 创建一个遵循WXModuleProtocol协议的 NSObject 类,并通过宏WX_EXPORT_METHOD将类中定义的方法暴露给Weex,而在native中执行完操作后,可以在设计接口处添加回调,通过block与对应Weex页面进行通信(比如传必要的参数给Weex页面),其中回调block有两种,WXModuleCallback 和 WXModuleKeepAliveCallback

    void (^WXModuleCallback)(id result):回调仅执行一次后释放
    void (^WXModuleKeepAliveCallback)(id result, BOOL keepAlive):回调一直存在,根据keepAlive的值来决定回调是仅执行一次还是一直保留。注意:回传的result数据可以是任意类型(NSDictionary, NSString, NSArray, Int, Float, Bool),因此要提前与编写Vue的童鞋约定好对应的格式

    - (void)showInfoFromWeexKeepAlive:(nullable NSDictionary *)infos keepAliveCallback:(nullable WXModuleKeepAliveCallback)callback {
        
        UIAlertController *alert = [[UIAlertController alloc] init];
        alert.title = @"Native Alert";
        alert.message = infos[@"message"];
        UIAlertAction *action0 = [UIAlertAction actionWithTitle:@"got it" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            
            callback(@{@"backInfo":@"confirm btn click"},true);
        }];
        
        UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"cancle" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            
            callback(@{@"backInfo":@"cancle btn click"},false);
        }];
        
        [alert addAction:action0];
        [alert addAction:action1];
        
        [UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];
        
       <!- 模拟block keepAlive场景 ->
        callback(@{@"backInfo":@"this is the first callback and keep block alive"},true);
    }
    
    • 然后在Appdelegate方法中初始化完Weex环境后,通过调用 WXSDKEngine 中的 registerModule:withClass方法来注册自己的Module,以便Weex能够识别并使用Native定义的Module
    WXSDKEngine.initSDKEnvironment()    
    WXSDKEngine.registerModule("YFTest", with: TestWXModule.classForCoder())
    
    

    vue.js端

    • 通过requireModule引入native定义的module,且需同名
    • 调用module中开放的API执行相关操作
    const nativeEvent = weex.requireModule('YFTest')
    export default {
      methods: {
    
        ......省略N多代码
        sendParamToNativeKeepAlive(event) {
          nativeEvent.showInfoFromWeexKeepAlive({"message":"show message from weex"}, function(ret) {
    
            var str = "";
            str = ret.backInfo;
            modal.confirm({
              message: "weex alert\n" + str,
              okTitle: 'i know'
            })
          });
        }
      }
    };
    

    坑:回调函数可能释放也可能一直存在,需要对不同的应用场景进行区分

    三、在写vue.js页面的发现在native上很多CSS的样式不支持

    • 简写均不支持,如:margin: 15px 15px 30px 30px;
    • 百分比不支持,如:width: 80%
    • 不能使用嵌套的CSS,布局上只支持flex
    • native上不存在全局样式,使用了预处理器也是不行(查了资料,web是可以有全局样式)
    • ue.js页面使用内置modal模块的toast时,无法屏蔽多次点击操作,需要特殊处理
    • weexView无法使用自动布局,渲染完成的weex页面的frame与weexInstance的frame保持一致

    四、页面之间的跳转

    • native -> weex:weex页面需要一个控制器作为容器, 此时就是native间的跳转
    • weex -> weex: 使用weex内置的navigator模块,weex之间传递数据需要用内置模块storage
    • weex -> native: 需要通过module形式通过发送事件到native来实现跳转(参照module的使用)

    附:降级方案参考文章

    饿了么
    飞猪
    根据接口配置,接口同时给native提供js文件和h5链接

    • 由后台决定Native使用何种方式加载(Weex | Web)
    • 如果后台指定使用weex,如果渲染失败(包括降级和其他一些会导致渲染失败的原因)则直接移除用来渲染weex页面的view,并改用webView来实现
      坑:如果使用webView来实现,页面之间的通信也就变成了hybrid方式,而不是前面讨论的weex-native之间的module方式
    weexInstance.onFailed = { [weak self] (view) in
         //渲染出错,包括降级,需要在这里切换至web展示
    }
    

    相关文章

      网友评论

          本文标题:Weex开发:页面间通信方式

          本文链接:https://www.haomeiwen.com/subject/sneskqtx.html