9

众所周知,不管是Flutter还是uni-app,其实都是一个UI框架,他们都是运行在原生系统之上的。自然,我们可以在Flutter工程中集成uni-app。

Android 集成uni-app

一、下载离线SDK

首先,我们创建一个Flutter普通应用,并使用Android Studio打开Android工程。接下来,打开uni-app官网,下载最新Android离线SDK,如下图所示。
在这里插入图片描述
解压后,可以使用Android Studio打开里面的项目HBuilder-Integrate-AS查看运行效果。打开下载的uni-app SDK目录,如下图所示。
在这里插入图片描述
SDK目录说明如下:

    |-- HBuilder-Hello                App离线打包演示应用
    |-- HBuilder-Integrate-AS        集成uni-app的最简示例
    |-- SDK                            SDK库文件目录
    |-- Feature-Android.xls            Android平台各扩展Feature API对应的详细配置
    |-- Readme.txt                    版本说明文件及注意事项
    |-- UniPlugin-Hello-AS            uni原生插件开发示例

二、 配置工程

2.1 基础库配置

然后,我们看一下如何在原生Android工程中集成uni-app SDK。如果还没有原生Android工程,可以新建一个。然后,将将lib.5plus.base-release.aar、android-gif-drawable-release@1.2.17.aar、uniapp-v8-release.aar和oaid_sdk_1.0.25.aar拷贝到libs目录下。
在这里插入图片描述

在build.gradle中添加资源引用,由于上面都是aar方式,那么只需要添加include: ['*.aar', '*.jar']即可引入进来。

 implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
 implementation "com.android.support:support-v4:28.0.0"
 implementation "com.android.support:appcompat-v7:28.0.0"
 implementation 'com.android.support:recyclerview-v7:28.0.0'
 implementation 'com.facebook.fresco:fresco:1.13.0'
 implementation "com.facebook.fresco:animated-gif:1.13.0"
 implementation 'com.github.bumptech.glide:glide:4.9.0'
 implementation 'com.alibaba:fastjson:1.1.46.android'

uni-app配置时还需要在build.gradle的android节点中添加aaptOptions配置,如下所示。

 aaptOptions {  
     additionalParameters '--auto-add-overlay'  
     ignoreAssetsPattern "!.svn:!.git:.*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~"  
 }

2.2 应用配置

配置Appkey

从3.1.10版本起,集成uni-app需要申请 Appkey,申请Appkey请参考
在这里插入图片描述
然后,打开Androidmanifest.xml, 导航到Application节点,创建meta-data节点,name为dcloud_appkey,value为申请的AppKey。

<application
  ...>
  <meta-data
      android:name="dcloud_appkey"
      android:value="替换为自己申请的Appkey" />
配置应用版本号

在这里插入图片描述
如果需要更改版本等信息,可以修改defaultConfig节点下面的配置。

  • versionCode:为应用的版本号(整数值),用于各应用市场的升级判断,建议与manifest.json中version -> code值一致
  • versionName:为应用的版本名称(字符串),在系统应用管理程序中显示的版本号,建议与manifest.json中version -> name值一致。
  • applicationId:为应用的包名,一般设置为反向域名,不建议修改。

同时,建议将targetSdkVersion设置为25或以上。App离线SDK minSdkVersion最低支持21,小于21在部分5.0以下机型上将无法正常使用。

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    defaultConfig {
        applicationId "com.example.myapplication"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
    implementation 'com.github.bumptech.glide:glide:4.9.0' // 基座依赖
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.alibaba:fastjson:1.1.46.android'
}
配置应用启动页及provider节点

打开Androidmanifest.xml文件,并且新建的项目默认会有一个MainActivity的节点,必须要删除,其他参考下面的代码添加。

 <activity
        android:name="io.dcloud.PandoraEntry"
        android:configChanges="orientation|keyboardHidden|keyboard|navigation"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:hardwareAccelerated="true"
        android:theme="@style/TranslucentTheme"
        android:screenOrientation="user"
        android:windowSoftInputMode="adjustResize" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name="io.dcloud.PandoraEntryActivity"
        android:launchMode="singleTask"
        android:configChanges="orientation|keyboardHidden|screenSize|mcc|mnc|fontScale|keyboard"
        android:hardwareAccelerated="true"
        android:permission="com.miui.securitycenter.permission.AppPermissionsEditor"
        android:screenOrientation="user"
        android:theme="@style/DCloudTheme"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="h56131bcf" />
        </intent-filter>
    </activity>
    <!--provider节点必须添加-->
    <provider
        android:name="io.dcloud.common.util.DCloud_FileProvider"
        android:authorities="${apk.applicationId}.dc.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/dcloud_file_provider" />
    </provider>
其他配置

正式打包之前,还需要配置应用图标和启动界面。

  • icon.png为应用的图标。
  • push.png为推送消息的图标。
  • splash.png为应用启动页的图标。

在这里插入图片描述
在这里插入图片描述
注意:splash.png在不同设备上显示效果不一样,为防止出现拉伸的状况,建议使用Android studio生成.9.png类型图片。

资源配置

手动新建一个assets文件夹,位置与java目录同级。然后,将SDK->assets->data文件夹拷贝到assets文件夹下,如下图所示。
在这里插入图片描述

然后,在assets文件夹下创建apps文件夹,并将HBuilderX项目导出的资源复制到assets->apps文件中,如下图所示。
在这里插入图片描述
生成HBuilderX项目资源可以参考:生成本地打包 APP 资源。选择项目 -> 发行 -> 原生App-本地打包 -> 生成本地打包App资源.
在这里插入图片描述

完成上述操作后,需要修改dcloud_control.xml文件,确保dcloud_control.xml中的appid与manifest.json中的id与文件夹名一致,如下图所示。
在这里插入图片描述
生成自定义基座,需要在根节点下添加debug="true"syncDebug="true",如下图。
在这里插入图片描述
这个自定义基座支持热更新需要将debug-server-release.aar打入apk中,生成正式包时可以删除,可以参考:详细步骤可参考链接

最后,按照Android代码的运行方式一样运行即可,效果如下图。
在这里插入图片描述

iOS集成uni-app

一、下载离线SDK

和原生iOS工程集成其他的SDK一样,在Flutter工程中集成uni-app需要先下载离线的SDK。打开uni-app官网,然后下载iOS的最新离线SDK
在这里插入图片描述

解压后,文件的目录结构如下图。
在这里插入图片描述

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

我们可以直接运行HBuilder-Hello 工程来查看运行效果。

二、 添加基础依赖库及资源文件

基础依赖库及资源是必须要引入到工程中的,基础依赖库及资源存放在 UniMPSDK/Core 目录,目录结构如下所示。

|-- UniMPSDK/Core
    |-- Headers          // .h 头文件
    |-- Libs             // 基础依赖库
    |-- Resources        // 资源文件

2.1 添加基础库

使用Xcode打开iOS工程,然后在 Xcode 项目左侧目录选中工程名,在 【TARGETS】->【Build Phases】->【 Link Binary With Libaries】 中点击【+】按钮,在弹出的窗口中点击 【Add Other】 ->【 Add Files...】,然后打开 UniMPSDK/Core/Libs 基础依赖库目录,选中目录中的 .a 库以及 .framework 库单击 open 按钮将依赖库添加到工程中。

在这里插入图片描述
在这里插入图片描述

2.2 添加系统依赖库

在 Xcode 项目左侧目录选中工程名,在 TARGETS->Build Phases-> Link Binary With Libaries 中点击“+”按钮,在弹出的窗口中查找并选择所需的库(见下表),单击 “Add” 按钮,将库文件添加到工程中。
在这里插入图片描述
需要依赖的库有如下一些:

  • JavaScriptCore.framework
  • CoreMedia.framework
  • MediaPlayer.framework
  • AVFoundation.framework
  • AVKit.framework
  • GLKit.framework
  • OpenGLES.framework
  • CoreText.framework
  • QuartzCore.framework
  • CoreGraphics.framework
  • libc++.tbd
  • QuickLook.framework
  • CoreTelephony.framework
  • AssetsLibrary.framework
  • CoreLocation.framework
  • AddressBook.framework
  • libiconv.tbd

2.3 添加依赖资源文件

接下来,还需要添加依赖资源文件,建议在项目中新建一个 Group来管理资源文件。如示例在工程目录中创建的 UniMP 文件夹,然后按功能模块创建不同的目录存放资源文件; 添加资源文件方法:在左侧目录中选中导入资源文件的位置(示例中是 UniMP/Core),在右键菜单中选择Add Files to “工程名...”,然后打开 UniMPSDK/Core 目录,选择 Resources 文件夹,然后点击“Add”,将资源文件添加到工程中。
在这里插入图片描述

2.4 添加 .h 头文件

在Xcode左侧目录中选中导入头文件的位置(示例中是 UniMP/Core),在右键菜单中选择Add Files to “工程名...”,然后打开 UniMPSDK/Core 目录,选择 Headers 文件夹,然后点击“Add”,将头文件资源添加到工程中。
在这里插入图片描述

生成小程序应用资源

首先在 HBuilderX 中选择您的 uni-app 项目,如果没有请新建一个 uni-app 项目,如下图。
在这里插入图片描述
然后,选中您的项目,右键->发行->原生App-制作应用wgt包。
在这里插入图片描述
点击“浏览” 选择wgt包导出路径,点击 “生成wgt”,如下图。
在这里插入图片描述
项目编译完成后会在控制台输出wgt包的路径,点击路径打开 wgt 资源包所在目录。
在这里插入图片描述

四、导入小程序资源

打开原生工程目录在 UniMP 路径中创建名称为Apps的文件夹,将之前导出的wgt包拷贝到Apps文件夹中,如下图。
在这里插入图片描述
然后,在原生工程中左侧目录中选中导资源文件的位置(示例中是 UniMP/),在右键菜单中选择Add Files to “工程名...”,然后打开工程目录,选择 Apps 文件夹,然后点击“Add”,将应用资源包添加到工程中,如下图所示。
在这里插入图片描述

五、修改代码

首先,需要初始化SDK引擎,并设置启动参数,建议在application:didFinishLaunchingWithOptions 方法中添加,在 AppDelegate.m 中引用头文件 #import "DCUniMP.h"#import "WeexSDK.h",如下所示。

#import "DCUniMP.h"
#import "WeexSDK.h"

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    // 配置参数
    NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:launchOptions];
    // 设置 debug YES 会在控制台输出 js log,默认不输出 log,注:需要引入 liblibLog.a 库
    [options setObject:[NSNumber numberWithBool:YES] forKey:@"debug"];
    // 初始化引擎
    [DCUniMPSDKEngine initSDKEnvironmentWithLaunchOptions:options];
    
    // 注册 module 注:module的 Name 需要保证唯一, class:为 module 的类名
    [WXSDKEngine registerModule:@"TestModule" withClass:NSClassFromString(@"TestModule")];
    // 注册 component 注:component 的 Name 需要保证唯一, class:为 component 的类名
    [WXSDKEngine registerComponent:@"testmap" withClass:NSClassFromString(@"TestMapComponent")];
    
    return YES;
}

然后,在 AppDelegate.m App 的生命周期方法中调用 SDK 相关方法,如下所示。

#pragma mark - App 生命周期方法
- (void)applicationDidBecomeActive:(UIApplication *)application {
    [DCUniMPSDKEngine applicationDidBecomeActive:application];
}

- (void)applicationWillResignActive:(UIApplication *)application {
    [DCUniMPSDKEngine applicationWillResignActive:application];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [DCUniMPSDKEngine applicationDidEnterBackground:application];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [DCUniMPSDKEngine applicationWillEnterForeground:application];
}

- (void)applicationWillTerminate:(UIApplication *)application {
    [DCUniMPSDKEngine destory];
}

并且,还可以根据项目需求实现以下方法。

#pragma mark - 如果需要使用 URL Scheme 或 通用链接相关功能,请实现以下方法
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    // 通过 url scheme 唤起 App
    [DCUniMPSDKEngine application:app openURL:url options:options];
    return YES;
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
    // 通过通用链接唤起 App
    [DCUniMPSDKEngine application:application continueUserActivity:userActivity];
    return YES;
}

接下来,需要打开小程序的文件中添加以下逻辑,参考示例工程 ViewController.m 。首先,需要引用头文件。

#import "DCUniMP.h"

添加代理协议, DCUniMPEngineDelegate类,如下。

@interface ViewController () <DCUniMPSDKEngineDelegate>
@end

小程序应用资源必须部署到指定的沙盒路径中才可以正常运行,如下。

/// 检查运行目录是否存在应用资源,不存在将应用资源部署到运行目录
- (void)checkUniMPResource {
    // 注意:isExistsApp: 方法仅是判断运行目录中是否存在应用资源,正式环境应该添加版本控制,内置新的wgt资源后需要判断版本,决定是否需要释放应用资源 
    if (![DCUniMPSDKEngine isExistsApp:k_AppId]) {
        // 读取导入到工程中的wgt应用资源
        NSString *appResourcePath = [[NSBundle mainBundle] pathForResource:k_AppId ofType:@"wgt"];
        // 将应用资源部署到运行路径中
        if ([DCUniMPSDKEngine releaseAppResourceToRunPathWithAppid:k_AppId resourceFilePath:appResourcePath]) {
            NSLog(@"应用资源文件部署成功");
        }
    }
}

最后是在原生代码中打开小程序的代码,如下。

/// 打开 uni 小程序
- (IBAction)openUniMP:(id)sender {
    // 初始化小程序的配置信息对象
    DCUniMPConfiguration *configuration = [[DCUniMPConfiguration alloc] init];
    [DCUniMPSDKEngine openUniMP:k_AppId configuration:configuration completed:^(DCUniMPInstance * _Nullable uniMPInstance, NSError * _Nullable error) {
        if (uniMPInstance) {
            // success
        } else {
            // error
        }
    }];
}

可以通过示例代码运行查看效果。


xiangzhihong
5.9k 声望15.3k 粉丝

著有《React Native移动开发实战》1,2,3、《Kotlin入门与实战》《Weex跨平台开发实战》、《Flutter跨平台开发与实战》1,2和《Android应用开发实战》