iOS控件

uni-app与iOS原生App的数据交互

2022-12-01  本文已影响0人  Joymerry

uni-app开发过程中,难免需要原生代码去处理业务逻辑,如何与原生进行数据交互就变得尤为重要。怎么传递数据,怎么接收数据,我们才能更好处理这些逻辑?下面我们就介绍一些uni-app与iOS原生的一些数据处理方式。

一、使用uni原生插件

这种方式是uniapp比较推荐的一种方式。但是实现起来比较依赖原生知识。不过这一部分交给原生端开发就可以了。

插件类型:

Module模式:不需要参与页面布局,只需要通过 API 调用原生功能,比如:获取当前定位信息、数据请求等功能,通过扩展module的方式来实现;
Component模式:需要参与页面布局,比如:map、image等需要显示UI的功能,通过扩展component即组件的方法来实现;

vue页面中仅支持使用Module类型的原生插件,不支持调用同步方法返回数据
nvue页面中支持使用Module和Component两种类型的原生插件。也就是如需实现嵌入页面的ui组件,前提是该页面需要使用nvue编写。

1.Module模式:

通过宏 UNI_EXPORT_METHOD 将异步方法暴露给 js 端,只有通过UNI_EXPORT_METHOD暴露的原生方法才能被 js 端识别到。
通过宏 UNI_EXPORT_METHOD_SYNC 将同步方法暴露给 js 端。

module 支持在 vue 和 nvue 中调用,添加如下代码

<template>
    <div>
        <button type="primary" @click="testAsyncFunc">testAsyncFunc</button>
        <button type="primary" @click="testSyncFunc">testSyncFunc</button>
    </div>
</template>

<script>
    // 首先需要通过 uni.requireNativePlugin("ModuleName") 获取 module 
    var testModule = uni.requireNativePlugin("DCTestUniPlugin-TestModule")
    export default {
        methods: {
            testAsyncFunc() {
                // 调用异步方法
                testModule.testAsyncFunc({
                        'name': 'uni-app',
                        'age': 1
                    },
                    (ret) => {
                        uni.showToast({
                            title:'调用异步方法 ' + ret,
                            icon: "none"
                        })
                    })
            },
            testSyncFunc() {
                // 调用同步方法
                var ret = testModule.testSyncFunc({
                    'name': 'uni-app',
                    'age': 1
                })

                uni.showToast({
                    title:'调用同步方法 ' + ret,
                    icon: "none"
                })
            }
        }
    }
</script>

2.component模式:

复写 DCUniComponent 中的生命周期方法

(1)liadView方法

一个组件默认对应一个原生 view,如果未复写loadView方法提供自定义view,会默认调用基类方法返回一个继承于 UIView 的实例。

(2)viewDidLoad

如果需要对组件view做一些配置,比如设置delegate,在 viewDidLoad 生命周期方法中是一个比较好的时机

在 uni-app 中使用组件

注意:扩展的 component 只能在 nvue 文件中使用,不需要引入即可直接使用

在uni-app项目中新建nvue文件

<template>
    <view>
        <dc-testmap style="width:750rpx;height:300px"></dc-testmap>
    </view>
</template>

自定义事件

<template>
    <div>
        <dc-testmap style="width:750rpx;height:300px" @mapLoaded="onMapLoaded"></dc-testmap>
    </div>
</template>

<script>
export default {
    methods: {
        onMapLoaded:function(e) {
            // 原生端传递的数据保存在 e.detail 中
            console.log("map loaded: "+JSON.stringify(e.detail))
        }
    }
}
</script>

在前端注册的mapLoaded方法,会在原生端调用addEvent:方法

如果需要原生端向前端发送事件,原生端在合适的时机调用fireEvent:params: domChanges:方法

自定义属性

给组建添加一个新的属性showTraffic

<template>
    <div>
        <dc-testmap style="width:750rpx;height:300px" showTraffic="true"></dc-testmap>
    </div>
</template>

对应原生端的实现,覆盖组件方法 onCreateComponentWithRef... 给组件添加一个成员变量记录 showTraffic 属性的值,并在 viewDidLoad 方法中初始化

-(void)onCreateComponentWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events uniInstance:(DCUniSDKInstance *)uniInstance
{
    if (attributes[@"showsTraffic"]) {
        _showsTraffic = [DCUniConvert BOOL: attributes[@"showsTraffic"]];
    }
}

onCreateComponentWithRef的方法是比viewDidLoad先进入的,所以可以先处理数据,然后在初始化方法viewDidLoad中进行一些操作

当前端更新属性时,会触发updateAttributes:方法,同步给地图控件

/// 前端更新属性回调方法
/// @param attributes 更新的属性
- (void)updateAttributes:(NSDictionary *)attributes {
    // 解析属性
    if (attributes[@"showsTraffic"]) {
        _showsTraffic = [DCUniConvert BOOL: attributes[@"showsTraffic"]];
        ((MKMapView*)self.view).showsTraffic = _showsTraffic;
    }
}

给组件添加方法

原生端实现

在组件代码中使用宏 UNI_EXPORT_METHOD 暴露原生方法供前端调用

@implementation TestMapComponent

// 通过 UNI_EXPORT_METHOD 将方法暴露给前端
UNI_EXPORT_METHOD(@selector(focus:))

// options 为前端传递的参数,支持 NSDictionary 或 NSString 类型
- (void)focus:(NSDictionary *)options {
    NSLog(@"%@",options);
}
@end

在 uni-app 中调用 focus: 方法

<template>
  <dc-testmap ref='mycomponent'></dc-testmap>
</template>
<script>
  module.exports = {
    created: function() {
      // 通过 this.$refs.mycomponent 获取地图组件
      // 调用组件 focus 方法
      this.$refs.mycomponent.focus({'value':'Hello'});
    }
  }
</script>

globalEvent 事件

在module 和 component中 用于页面监听持久性事件,例如定位信息,陀螺仪等的变化。

globalEvent事件只能通过页面的DCUniSDKInstance实例给当前页面发送globalEvent事件。其他页面无法接受。

示例:

页面监听event事件

var globalEvent = uni.requireNativePlugin('globalEvent');
globalEvent.addEventListener('myEvent', function(e) {
  console.log('myEvent'+JSON.stringify(e));
});

在原生代码 发出myEvent事件

NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:@"value",@"key",nil];
NSString * eventName = @"myEvent";
DCUniSDKInstance * instance = self.uniInstance;
[instance fireGlobalEvent:eventName params:params];

二、HTML5 plus api中的Native.js方法

这种方式的话,使用起来非常简单,我们只需要在app原生端创建一个类,使用这个类接手uni-app的调用方法即可。
在uni-app端根据native 的api去创建对应的原生类,然后使用原生类去调用原生方法,进行传参就能进行简单的数据交互。

uni-app端的代码实现:

let newVCobj = plus.ios.newObject('MessageHand');
plus.ios.invoke(newVCobj, 'jump:', userInfo);

原生端的代码实现

-(void)jump:(NSDictionary *)userInfo {
    dispatch_async(dispatch_get_main_queue(), ^{
        HomeViewController * homeVC = [[HomeViewController alloc]init];
        homeVC.userInfo = userInfo;
        AppDelegate * delegate=(AppDelegate*)[[UIApplication sharedApplication] delegate];
        delegate.rootViewController.navigationBarHidden = NO;
        [delegate.rootViewController pushViewController:homeVC animated:YES];
    });
}

native.js如何获取原生的数据呢?这个问题就稍微复杂,从H5+ api中没有找到文档讲解,在网上查也没有查到好的办法,但是可以通过两种方式。

第一,uni-app端主动获取。我们可以在原生定一个getInfo的方法,让uni-app去主动获取。

let newVCobj = plus.ios.newObject('MessageHand');
plus.ios.invoke(newVCobj, 'getInfo');

原生端的代码实现

-(NSString*)getInfo {
    return @“”;
}

第二种方式的话,通过回调方法去拿到数据。

let messageHand = plus.ios.newObject('MessageHand');
let delegate = plus.ios.invoke(messageHand,'getInfoCallBack:', (e)=>{
// 可以拿到事件,但是拿不到e数据值
});

原生端的代码实现

-(NSString*) getInfoCallBack:(void(^)(NSString * _Nonnull timer))handleBlock{
    handleBlock(@"nihao");
    return @"wohenhao";
}

但是第二种方式有一个问题就是,如果在回调方法中我是拿不到预期的结果值,那又如何传递给uni-app端数据。

上一篇下一篇

猜你喜欢

热点阅读