iOS 基于 uniapp 原生组件开发,原生部分如何处理Vue页面跳转。

1,727 阅读4分钟

废话开篇:iOS 下的导航器是基于 UINavigationController 的,由它负责对控制的跳转逻辑。vue下是依靠的是路由 router,当然这只是在网页的环境下,那么,uniapp 在移动端下进行页面跳转是通过 navigateTo 进行的,这里需要值得说一下的是:uniapp 在页面进行跳转的过程中是处理了控制器之间的关系的,也就是说,每一个vue或者nvue,都会挂载到一个新的 UIViewController

一、实现效果

封装一个播放器组件,那么,这里需要用到 uni 的组件开发工具,可以到 uni组件开发文档下载。

由于是要做 UI 原生组件,那么 HbuilderX 在创建前端文件到时候就必须使用 .nvue 文件进行代码编写;在 iOS 原生库中要用 DCUniComponent 类来进行组件开发。

说了这么多,先看一下效果。

屏幕录制2022-02-21 上午10.42.43.gif

这里把步骤拆开:

1、vue 界面中点击“进入视频详情” 由 vue 执行 uni.navigateTo 跳转到 iOS 原生播放器挂载的 nvue 界面。

gotoVideo(){
    uni.navigateTo({
	url:'./wslAVPlayer',
	success: res => {},fail: (error) => {
			},complete: () => {}
	   })
}

2、点击视频小屏播放功能按钮,uni 执行回退操作;并通过 iOS 原生将视频小屏展示在屏幕上,这里放的是 keyWindow 上。

enterSmallScreen(){
	uni.navigateBack({
		delta:1,
		success: res => {},fail: (error) => {
		 },complete: () => {
		}
	})
}

3、点击小屏放大浏览功能按钮,进行正常界面播放展示。

二、实现过程中存在的问题

这里需要先说一下,iOS 组件扩展类 DCUniComponent 和 功能扩展类 DCUniModule 都是可以和 uni 组件进行通信的。但是,像上面的事例,在通过 uni 进行回退的时候,退回消失页面里面的原生组件及前端对象就会销毁,即使 iOS 原生部分强持有视频播放器,但是与视频播放器进行交互的前端组件对象可能销毁了,无法再接受消息了,或者说,即使通过什么方法可以进行交互,那么,再推出之前的页面,可能也会导致前端路由混乱。所以如果再想通过uni 进行页面跳转,那么就需要一个常驻前端通信对象,在 uni 前端代码初始化开始的地方就进行常驻前端通信对象初始化。那么,在进行小屏转正常播放的时,就用这个常驻前端通信对象进行页面入栈操作。

三、创建前端常驻通信对象

创建 WSLBaseModule 类,继承自 DCUniModule

iOS 代码:

#import "WSLBaseModule.h"
#import "WSLStaticCustomConfig.h"

@interface WSLBaseModule()

//保存前端的回调
@property(nonatomic,copy) UniModuleKeepAliveCallback pushPlayerCallBack;

@end

@implementation WSLBaseModule

UNI_EXPORT_METHOD( @selector(shouldPushPlayerViewFunc:callback:))

//跳转到正常播放状态事件
- (void)shouldPushPlayerViewFunc:(NSDictionary *)options callback:(UniModuleKeepAliveCallback)callback
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(enterNormalScreenAction) name:enterNormalScreen object:nil];
    if (callback) {
        self.pushPlayerCallBack = callback;
    }
}

//接受正常播放通知
- (void)enterNormalScreenAction
{
    if (self.pushPlayerCallBack) {
        self.pushPlayerCallBack(@{}, YES);
    }
}

这里别忘了在 info.plist 文件下添加对 iOS 原生对象和 uni 对象的映射关系

image.png

uni 代码:

onLoad() {
    var baseModule = uni.requireNativePlugin("WSLBaseModule");
    //推出正常播放界面
    baseModule.shouldPushPlayerViewFunc(
			   {},
			   (ret) => {
			         uni.navigateTo({
			             	url:'./wslAVPlayer',
			             	success: res => {},fail: (error) => {
			             	},complete: () => {}
			   })
                       }
	          )
}

解释一下:

1、在 uni 工程的初始化界面下比如 APP.vue 里进行 WSLBaseModule 对象的初始化。在页面的 onload 方法里进行执行 shouldPushPlayerViewFunc 的操作,目的就是将回调传给原生并进行属性持有

2、当小屏播放器被要求进行正常页面播放时,那么,就发一个通知,让 iOS 原生的 WSLBaseModule 对象执行回调属性,那么,uni 前端映射对象在特定时机就会调用 callback 推出正常播放视频视图了。

3、优化地方。uniapp 当推出正常播放界面时,原生这里其实是可以将原播放数据,比如播放进度等信息回传给前端的,那么,就实现了无缝大小屏切换的功能。

四、总结思考

vue 如果仅仅是PC端而不是移动端的话,它会有一个全局对象,来共享信息,也很好理解,就好比大家都在一个 JS 运行环境下,那么,有什么不能说的呢?但是移动端下,就必须进行各种通信,当然也可以理解为:大家都在 iOS 系统下,又有啥获取不到的呢?

这里仅仅是个人理解,uniapp 组件开发感兴趣的朋友可以到官网下一个体验体验,有啥新的思路,希望大家指教。代码拙劣,大神勿笑。