Weex开发:页面间通信方式

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];
    
   
    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开发:页面间通信方式)