小程序容器化:基于uni-app的iOS小程序开发

小程序容器化:基于uni-app的iOS小程序开发,第1张

前言      

       相信越来越多小伙伴发现不少超级APP的页面都采用小程序开发了。例如支付宝客户端,首页有一个小程序中心的入口,支付宝上很多页面都是小程序了。

图1 支付宝小程序入口

       第一次打开的一个新功能时,会出现一个短暂的loading过程。小程序右上角有查看详情和关闭的按钮,例如中国体育小程序。

图2 支付宝“中国体育”小程序截图

       那么为什么越多越多大厂的app采用了小程序容器化开发呢?博主将在本博客简要说明小程序容器化的趋势、优点,以及如何基于uni-app在iOS端开发自己的小程序。本文提纲如下:

图3 博客提纲
 一. 小程序趋势

       回到前言提到的问题——那么为什么越多越多大厂的app采用了小程序容器化开发呢?这是大前端发展的趋势。博主认为主要有以下几个原因:

1.1多端一致性

        Android/iOS双端一致性,一直是移动端致力解决的问题。一些热门产品,通常还有PC端、公众号、H5页面等门户产品。在博主的项目中就要求四端:Android、iOS、PC端、H5提供交易功能。同样的功能,实现了四遍,测试四遍。跨平台技术是保证多端一致性的重要手段。

1.2 动态化

        动态化,不仅可以满足千人千面的需求,通过后台配置模版实现页面动态化,不需要客户端coding大量的代码;还可以减少app发版的次数和降低上架时间,日渐严格的苹果市场审核机制让开发者意识到动态化的重要性,尤其是出现BUG时需要紧急发版。对于强监管业务,app也是需要具备随时下架某个功能的能力。

1.3 低代码,提升开发效率

       low- code——低代码,这在业界已经流行好多年了。low- code可以大幅度减少代码量,通过模版代码就能快速满足功能开发或支持第三方接入的需求。同一套模版代码还可以复用到各个端,开发量减少了,测试时间也减少了,开发效率得到极大的提升。

1.4 安装包控制

       大厂的超级app通常包罗很多功能,还是拿支付宝来说,支付宝上面的多功多得数不清。如果用纯原生的代码来实现,想想app安装包会大到什么程序?这对app推广非常不利的。所以,控制 app安装包大小,web或小程序化就变成非常重要了 。

二. 为什么选择uni-app

       市面上能满足开发并集成自己的小程序的技术还挺多的,例如AntBuilder、FinClip、uni-app等。没有最好的技术,只有适合自己团队和业务场景的技术才是最佳的技术,所以博主不会展开讨论它们的区别,而是从自身的角度谈谈为什么选择uni-app。

2.1 技术栈

       uni-app技术栈还是基于vue.js + weex的,比较符合我们团队的技术储备的情况,学习成本非常低,团队能快速上手。

2.2 uni-app的特点

       uni-app从2018年发布第一个版本以来,一直保持快速迭代的趋势[1] 。官方github上star数量为:32.7K[2]。uni-app在开发者数量、案例、跨端抹平度、扩展灵活性、性能体验、周边生态、学习成本、开发成本等关键指标上拥有更强的优势[3]。

1)开发者/案例数量更多:数百万应用、uni统计月活12亿、70+微信/qq群、更高的百度指数,跨端完善度高。

2)平台能力不受限:在跨端的同时,通过条件编译+平台特有API调用,可以优雅的为某平台写个性化代码,调用专有能力而不影响其他平台。支持原生代码混写和原生sdk集成。

3)性能体验优秀:加载新页面速度更快、自动diff更新数据。App端支持原生渲染,可支撑更流畅的用户体验。小程序端的性能优于市场其他框架。

4)周边生态丰富:插件市场数千款插件。支持NPM、支持小程序组件和SDK。微信生态的各种sdk可直接用于跨平台App。

5)学习成本低:基于通用的前端技术栈,采用vue语法+微信小程序api,无额外学习成本。

6)开发成本低: HBuilderX是高效开发神器,熟练掌握后研发效率至少翻倍。

三. 集成uni-app   3.1 安装环境

       环境安装参考官网[4],uni-app支持通过可视化界面、vue-cli命令行两种方式快速创建项目。推荐大家使用可视化界面。可视化的方式比较简单,HBuilderX内置相关环境,开箱即用,无需配置nodejs。

       开始之前,开发者需先下载安装HBuilderX IDE工具:

安装HBuilderX:官方IDE下载地址

        HBuilderX是通用的前端开发工具,但为uni-app做了特别强化。分两个版本:1)App开发版,可开箱即用;2)标准版,在运行或发行uni-app时,会提示安装uni-app插件,插件下载完成后方可使用。推荐下载App开发版,博主安装的MacOS 开发版。

图3.1 HBuilderX安装包
 下载SDK:从官网下载最新版本的SDK[5], 下载链接。如下图所示:
图3.2 下载SDK
   3.2 集成 SDK    添加依赖

       1)在主工程下面创建一个group: Uniapp,然后把SDK的Core下面的Headers、Resources、Libs这三个文件夹拷贝到Uniapp group。

       2)右键Uniapp,add files到工程。

图3.1 添加SDK的Core文件到工程
图3.2 添加文件

     3)在Build phases中添加以下 lib:

图3.3 添加依赖库

 4)Build Settings -> Other Linker Flags,添加-ObjC。

图3.4 Build Settings添加Other Linker Flags
 SDK初始化:

   1)在AppDelegate中添加uni-app初始化代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = [[UniappViewController alloc]init];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    
    [self initUniappSDK:launchOptions];
    
    return YES;
}

-(void) initUniappSDK:(NSDictionary *)launchOptions {
    // 配置参数
    NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:launchOptions];
    // 设置 debug YES 会在控制台输出 js log,默认不输出 log,注:需要引入 liblibLog.a 库
    [options setObject:[NSNumber numberWithBool:YES] forKey:@"debug"];
    // 初始化引擎
    [DCUniMPSDKEngine initSDKEnvironmentWithLaunchOptions:options];
}

2)监听App 生命周期方法

#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];
}

3)可选,非必须:如果用到以下AppDelegate的回调,则实现对应的方法。没用到则不需要实现。

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

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

#pragma mark - 如需使用远程推送相关功能,请实现以下方法
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    // 远程通知注册成功,收到 deviceToken 调用sdk方法,传入 deviceToken
    [DCUniMPSDKEngine application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    // 远程通知注册失败
    [DCUniMPSDKEngine application:application didFailToRegisterForRemoteNotificationsWithError:error];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // 收到远程推送消息
    [DCUniMPSDKEngine application:application didReceiveRemoteNotification:userInfo];
    completionHandler(UIBackgroundFetchResultNewData);
}

#pragma mark - 如需使用本地推送通知功能,请实现以下方法
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    // 收到本地推送消息
    [DCUniMPSDKEngine application:application didReceiveLocalNotification:notification];
}
 加载测试小程序:

   1)在Uniapp下创建一个group: apps,sdk解压缩包HelloUniMPDemo/UniMP/Apps拷贝一个wgt到apps下面。

图3.5 添加app group及拷贝wgt测试包

 2)添加加载测试小程序逻辑。

/// 启动小程序
- (void)openUniMP {
    // 获取配置信息
    DCUniMPConfiguration *configuration = [self getUniMPConfiguration];
    
    // 配置启动小程序时传递的参数(参数可以在小程序中通过 plus.runtime.arguments 获取此参数)
    configuration.arguments = @{ @"arguments":@"Hello uni microprogram" };
    
    __weak __typeof(self)weakSelf = self;
    // 打开小程序
    [DCUniMPSDKEngine openUniMP:k_AppId configuration:configuration completed:^(DCUniMPInstance * _Nullable uniMPInstance, NSError * _Nullable error) {
        if (uniMPInstance) {
            weakSelf.uniMPInstance = uniMPInstance;
        } else {
            NSLog(@"打开小程序出错:%@",error);
        }
    }];
}

3) 实现DCUniMPSDKEngineDelegate的方法。

  完整的代码如下:

#import "UniappViewController.h"
#import "DCUniMP.h"

#define k_AppId @"__UNI__11E9B73" // 小程序名称

@interface UniappViewController ()

@property (nonatomic, weak) DCUniMPInstance *uniMPInstance; // 声明DCUniMPInstance

@end

@implementation UniappViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelTouchUpInside:)];
    
    UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(100,100, 100,100)];
    lable.text = @"打开小程序";
    lable.textColor = [UIColor redColor];
    lable.userInteractionEnabled = YES;
    [lable addGestureRecognizer:tap];
    
    [self.view addSubview:lable];
    
    [self checkUniMPResource];
}

-(void) labelTouchUpInside:(UITapGestureRecognizer *)recognizer{
   UILabel *label=(UILabel*)recognizer.view;
   NSLog(@"%@被点击了",label.text);
    
    [self openUniMP];
}
/// 小程序配置信息
- (DCUniMPConfiguration *)getUniMPConfiguration {
    /// 初始化小程序的配置信息
    DCUniMPConfiguration *configuration = [[DCUniMPConfiguration alloc] init];
    
    // 开启后台运行
    configuration.enableBackground = YES;
    // 设置 push 打开方式
    configuration.openMode = DCUniMPOpenModePush;
    // 启用侧滑手势关闭小程序
    configuration.enableGestureClose = YES;
    
    return configuration;
}

/// 检查运行目录是否存在应用资源,不存在将应用资源部署到运行目录
- (void)checkUniMPResource {
    if (![DCUniMPSDKEngine isExistsApp:k_AppId]) {
        // 读取导入到工程中的wgt应用资源
        NSString *appResourcePath = [[NSBundle mainBundle] pathForResource:k_AppId ofType:@"wgt"];
        if (!appResourcePath) {
            NSLog(@"资源路径不正确,请检查");
            return;
        }
        // 将应用资源部署到运行路径中
        if ([DCUniMPSDKEngine releaseAppResourceToRunPathWithAppid:k_AppId resourceFilePath:appResourcePath]) {
            NSLog(@"小程序 %@ 应用资源文件部署成功",k_AppId);
        }
        
        // 设置 delegate
        [DCUniMPSDKEngine setDelegate:self];
    }
}

/// 启动小程序
- (void)openUniMP {
    // 获取配置信息
    DCUniMPConfiguration *configuration = [self getUniMPConfiguration];
    
    // 配置启动小程序时传递的参数(参数可以在小程序中通过 plus.runtime.arguments 获取此参数)
    configuration.arguments = @{ @"arguments":@"Hello uni microprogram" };
    
    __weak __typeof(self)weakSelf = self;
    // 打开小程序
    [DCUniMPSDKEngine openUniMP:k_AppId configuration:configuration completed:^(DCUniMPInstance * _Nullable uniMPInstance, NSError * _Nullable error) {
        if (uniMPInstance) {
            weakSelf.uniMPInstance = uniMPInstance;
        } else {
            NSLog(@"打开小程序出错:%@",error);
        }
    }];
}

#pragma mark - DCUniMPSDKEngineDelegate
/// DCUniMPMenuActionSheetItem 点击触发回调方法
- (void)defaultMenuItemClicked:(NSString *)identifier {
    NSLog(@"标识为 %@ 的 item 被点击了", identifier);
    
    // 将小程序隐藏到后台
    if ([identifier isEqualToString:@"enterBackground"]) {
        __weak __typeof(self)weakSelf = self;
        [self.uniMPInstance hideWithCompletion:^(BOOL success, NSError * _Nullable error) {
            if (success) {
                NSLog(@"小程序 %@ 进入后台",weakSelf.uniMPInstance.appid);
            } else {
                NSLog(@"hide 小程序出错:%@",error);
            }
        }];
    }
    // 关闭小程序
    else if ([identifier isEqualToString:@"closeUniMP"]) {
        [self.uniMPInstance closeWithCompletion:^(BOOL success, NSError * _Nullable error) {
            if (success) {
                NSLog(@"小程序 closed");
            } else {
                NSLog(@"close 小程序出错:%@",error);
            }
        }];
    }
    // 向小程序发送消息
    else if ([identifier isEqualToString:@"SendUniMPEvent"]) {
        [DCUniMPSDKEngine sendUniMPEvent:@"NativeEvent" data:@{@"msg":@"native message"}];
    }
}

/// 返回打开小程序时的自定义闪屏视图
- (UIView *)splashViewForApp:(NSString *)appid {
    UIView *splashView = [[[NSBundle mainBundle] loadNibNamed:@"SplashView" owner:self options:nil] lastObject];
    return splashView;
}

/// 小程序关闭回调方法
- (void)uniMPOnClose:(NSString *)appid {
    NSLog(@"小程序 %@ 被关闭了",appid);
    
    self.uniMPInstance = nil;
}

/// 监听小程序发送的事件回调方法
/// @param event 事件
/// @param data 参数
/// @param callback 回调方法,回传数据给小程序
- (void)onUniMPEventReceive:(NSString *)event data:(id)data callback:(DCUniMPKeepAliveCallback)callback {
    
    NSLog(@"Receive UniMP event: %@ data: %@",event,data);
    // 回传数据给小程序
    // DCUniMPKeepAliveCallback 用法请查看定义说明
    if (callback) {
        callback(@"native callback message",NO);
    }
}

@end

在Xcode中运行代码,看到测试小程序被正常调起了,说明uni-app集成OK了。

图3.6 测试小程序加载图

四. 编写并运行自己的小程序   4.1 编写小程序 打开HBuilderX,文件->新建->项目,项目信息如下:
图4.1 HBuilderX创建项目界面

创建好目录之后,我们来看看工程的代码结构。

图4.2 工程的代码结构

 1)pages:页面布局写在这下面;

 2)manifest.json:小程序的配置文件,选择性配置一些信息,如下图所示。前提:你需要到dcloud开发者中心官网注册一个账号,注册地址。在后台创建一个应用,如下图所示。

图3.7 dcloud开发者中心后台应用列表截图
图4.3 manifest.json配置图

3)pages.json:页面路由配置及全局样式。例如:

{
    "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
        {
            "path": "pages/about/about",
            "style": {
                "navigationBarTitleText": "关于"
            }
        }
    ],
    "globalStyle": {
        "navigationBarTextStyle": "black",
        "navigationBarTitleText": "关于",
        "navigationBarBackgroundColor": "#F8F8F8",
        "backgroundColor": "#F8F8F8"
    }
}

  4.2 运行小程序   

     点击HBuilderX左上角的运行按钮,选择编译设备,例如chrome浏览器。 

图4.4 HBuilderX编译选择界面
  4.3 打包小程序 代码运行没有问题,就可以打包了。打开HBuilderX,点击左上角的发行按钮,生成wgt包 。
图4.5 HBuilderX打包界面
4.4 集成小程序

  将生成的wgt包拷贝到Uniapp/apps下。

图4.6 将小程序包拷贝到apps
4.5 运行小程序

     在调起小程序的入口,将名字改为我们的小程序名称即可。

#define k_AppId @"__UNI__C0C0F45" // 小程序名称

在Xcode中代码,看到我们的小程序被加载进来了。 

图4.7 小程序加载页面
5.Demo代码

     demo代码上传到github,如果需要,请小伙伴自行下载。下载地址。

6.参考链接

[1] https://uniapp.dcloud.io/release?id=_014520180728-alpha

[2] https://github.com/dcloudio/uni-app

[3] https://uniapp.dcloud.io/README

[4] https://uniapp.dcloud.io/quickstart-hx

[5]https://nativesupport.dcloud.net.cn/UniMPDocs/SDKDownload/ios

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/993986.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存