先说一下项目背景,uni-app开发同事已经写好的项目,需要用到一个iOS原生的视频上传SDK,uni-app开发同事将录制好的视频路径从uni-app传递给iOS原生,iOS原生使用视频上传SDK将视频上传成功以后,需要在回调中再将参数回传给uni-app

这里我分为几个阶段去进行讲解

一、项目配置修改

可以先看一下uni官方的集成教程
安装完所需要的编辑器以后,需要下载App离线SDK
找到App离线SDK压缩包,解压后进入目录,找到HBuilder-Hello文件夹,打开原生工程,然后准备配置工程。
HBuilder-Hello文件夹下的打包工程 是按照uni-app项目来配置的,所以基础配置不需要动。

App离线SDK.png

 

SDK目录说明

|-- HBuilder-Hello 给用户打uni-app项目的离线打包工程
|-- Feature-iOS.xls 配置表(依赖的库、资源文件、参数配置等)
|-- SDK 工程需要的库文件,.h头文件,配置文件,资源文件

打开项目后,bundle ID无法修改,需要在signing & Capabilities 中修改Team 和 bundle ID
修改完以后,debug这里产生了这样的警告。

debug警告.png

HBuilder has conflicting provisioning settings.
HBuilder is automatically signed, but provisioning profile a7e03077-46db-4b91-b0c4-20fd613c1e14 has been manually specified. Set the provisioning profile value to "Automatic" in the build settings editor, or switch to manual signing in the Signing & Capabilities editor.

修复方式很简单,将警告图中选中的这段标识复制,然后在build setting里面搜索,找到以后删除掉这段内容。

搜索结果.png

release这里也有一个警告

HBuilder has conflicting provisioning settings.
HBuilder is automatically signed for development, but a conflicting code signing identity iPhone Distribution has been manually specified. Set the code signing identity value to "Apple Development" in the build settings editor, or switch to manual signing in the Signing & Capabilities editor.

解决方式也很简单,在build setting 中搜索 signing,将code signing identity 全部改为 apple development,然后关闭项目重新打开就可以了。

code signing identity.png

3.1.10版本起需要申请Appkey,先去申请Appkey

申请Appkey.png

申请成功后,打开info.plist创建keydcloud_appkeyValue选择String类型,内容为申请的AppKey

info-plist-appkey-config.png

用离线打包工程制作自定义调试基座

1、在打包原生工程里找到control.xml文件,在HBuilder节点里查看是否有这2个: debug="true" syncDebug="true" 配置(注意打AppStore包的时候,这个配置需要去掉,否则会导致热更新失败!),没有的话增加上,然后保存。

2、 确保Xcode工程的Bundle identifier不为 io.dcloud.HBuidler

3、在原生工程里找到info.plist文件并增加一项,如下图:

4、确保原生工程里Pandora文件夹下的apps文件夹里只有一个文件夹(文件夹的名称和里面的manifest的id值相同)

5、确保control.xml文件里的appid的值和apps目录下的第一个文件夹的名称一致

6、确保HBuilderX里要调试的代码的appid和control.xml的appid值一致

也就是要保证图中三个文件与所框的内容一致

7、使用Xcode的Product下的archive 打包,然后生成ipa,并把ipa名称命名为:iOS_debug.ipa

8、在js工程里主目录下新建一个名称为unpackage的文件夹(如果有不用新建),再在unpackage文件夹下新建一个名称为debug文件夹,并把生成的iOS_debug.ipa包放入debug文件夹。

debug.png

9、在HBuildX里,找到之前appid相同的js工程准备调试,点击“运行” --“运行到手机或模拟器“--“使用自定义基座运行(iOS)”,等待连接成功之后就可以了。

10、连接手机,编译运行,如果App成功跑起来了,说明原生工程配置完成。

然后在HBuilderX中,选中项目文件夹,右键选择发行->原生APP本地打包->生成本地打包App资源

生成本地打包App资源.png

等待HBuilderX编译成功以后会在控制台输出生成的资源路径,点击路径就能看到和一个和iOS原生工程里Pandora文件夹下的apps文件夹里一个同名的文件夹文件夹

生成的路径.png

点击后看到的同名文件夹.png

然后我们将iOS项目目录下的 Pandora -> apps 路径下的这个文件夹删除掉,替换成资源路径里的文件夹。删除掉手机里的旧程序,就可以运行了。

这里需要注意,前端代码修改后重新导入资源时,需要在xcode工程中删除之前导入的资源,同时将手机里的旧App程序删除,防止因为缓存问题导致加载的还是旧的资源

二、集成所需视频上传SDK

这部分没什么太多可讲的内容,主要就是SDK集成,但是这里遇到一个集成的问题需要注意一下。
集成完以后,编译会报错

报错.png

解决方法如图,在 other linker flags里面添加一行 $(inherited)
还有另一个报错,bitcode bundle could not be generated because

解决操作为在Build Settings中搜索Enable Bitcode,将值设置为No
然后在Project-> Targets-> Build Settings-> Custom Compiler Flags-> Other C Flags 添加一行,内容为 "-fembed-bitcode"

三、两平台交互

uni官方的原生插件教程
uni原生插件指的是将您原生开发的功能按照规范封装成插件包,然后即可在 uni-app 前端项目中通过js调用您开发的原生能力。

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

这里我们只是用了视频上传功能,和页面布局没有关系,所以使用module 就足够了。

在iOS原生平台暴露接口给uni-app

新建AppModule类,继承 DCUniModule,引入 DCUniModule.h 头文件。

#import <Foundation/Foundation.h>
// 引入 DCUniModule.h 头文件
#import "DCUniModule.h"

@interface AppModule : DCUniModule

@end

然后在 AppModule.m 文件中添加实现方法

异步方法实现

/// 异步方法(注:异步方法会在主线程(UI线程)执行)
/// @param options js 端调用方法时传递的参数   支持:String、Number、Boolean、JsonObject 类型
/// @param callback 回调方法,回传参数给 js 端   支持: NSString、NSDictionary(只能包含基本数据类型)、NSNumber 类型
- (void)testAsyncFunc:(NSDictionary *)options callback:(UniModuleKeepAliveCallback)callback { 

    // options 为 js 端调用此方法时传递的参数 NSLog(@"%@",options); // 可以在该方法中实现原生能力,然后通过 callback 回调到 js 

   if (callback) {
       // 第一个参数为回传给js端的数据,第二个参数为标识,表示该回调方法是否支持多次调用,如果原生端需要多次回调js端则第二个参数传 YES;
        callback(@"success",NO);

    }
}

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

// 通过宏 UNI_EXPORT_METHOD 将异步方法暴露给 js 端
UNI_EXPORT_METHOD(@selector(testAsyncFunc:callback:))

同步方法实现

/// 同步方法(注:同步方法会在 js 线程执行)
/// @param options js 端调用方法时传递的参数   支持:String、Number、Boolean、JsonObject 类型
- (NSString *)testSyncFunc:(NSDictionary *)options {
    // options 为 js 端调用此方法时传递的参数
    NSLog(@"%@",options);

    /*
     可以在该方法中实现原生功能,然后直接通过 return 返回参数给 js
     */

    // 同步返回参数给 js 端  支持:NSString、NSDictionary(只能包含基本数据类型)、NSNumber 类型
    return @"success";
}

通过宏 UNI_EXPORT_METHOD_SYNC 将同步方法暴露给 js 端

// 通过宏 UNI_EXPORT_METHOD_SYNC 将同步方法暴露给 js 端
UNI_EXPORT_METHOD_SYNC(@selector(testSyncFunc:))

如果需要在 App 启动时初始化或者需要获取系统的一些事件, 需要新建一个XXXXProxy类(注意命名加前缀防止冲突),继承 NSObject 遵守UniPluginProtocol协议。这个功能项目中没有用到,不在此赘述。如有需求,可以查看官方教程相关内容。

配置插件信息

选中工程中的HBuilder-uniPlugin-Info.plist文件右键Open As->Source Code找到dcloud_uniplugins节点,拷贝下面的内容添加到dcloud_uniplugins节点下,按您插件的实际信息填写对应的项

<dict>
    <key>hooksClass</key>
    <string>填写 hooksClass 类名 </string>
    <key>plugins</key>
    <array>
        <dict>
            <key>class</key>
            <string>填写 module 或 component 的类名</string>
            <key>name</key>
            <string>填写暴露给js端对应的 module 或 component 名称</string>
            <key>type</key>
            <string>填写 module 或 component</string>
        </dict>
    </array>
</dict>

如果不在HBuilder-uniPlugin-Info.plist正确配置这些键值对,手机运行以后,控制台会报警告

<Weex>[warn]WXBridgeContext.m:1310, jsLog: [JS Framework] 当前运行的基座不包含原生插件[HBuilder-Hello-AppModule],请在manifest中配置该插件,重新制作包括该原生插件的自定义运行基座 __WARN

在 uni-app 项目中调用 module 方法

<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("HBuilder-Hello-AppModule")
    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>

这个时候我们就可以按照上面已经说过的方法生成 uni-app 项目的本地打包资源,将资源放入到xcode中的相应路径下,测试uni-app调用iOS原生功能是否正常了。


番外篇

当在手机成功运行以后,需要调用相机录制视频,点击录制按钮调用相机功能时,出现HTML5+Runtime打包时未添加Camera模块弹窗警告且相机不能正常调用,这是因为调用了相关模块的 API 但是原生工程没有添加相关依赖导致的。

缺少camera模块.jpeg

具体缺少哪个模块,可以参考下载的SDK目录下Feature-iOS.xls功能模块配置表。例如我这里是需要调用相机,缺少camera模块,那么就看camera模块需要配置什么。

缺少的配置

build phases中的link binary with libraries中添加上缺少的六个库文件即可。
build settings 中的other linker flags添加一行-llibCamera
再次运行,相机功能可以正常调用了。

通过路径获取沙盒文件
这里又遇到了一个坑,当在uni-app中使用相机拍摄了视频以后,使用uni.chooseVideo方法获取到的视频路径为_doc/uniapp_temp_1655703702857/camera/video_001.mp4,我们一眼就能看出来,这个地址肯定不是我们想要的地址,因为iOS沙盒地址不是这种格式的,我们需要转一下才能用。

//res = "_doc/uniapp_temp_1655703702857/camera/video_001.mp4";
//这样转换以后,就是iOS沙盒的路径了。
var path = plus.io.convertLocalFileSystemURL(res);

如果需要需要调用uni-appuploadFile方法进行上传,需要在path路径前面再拼接一下

path = 'file://' + path;

如果文件名中包含中文,需要使用decodeURIComponent(path),将地址的url进行反编码。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐