前言
最近公司产品有个需求,为我们app中每个H5应用实现添加桌面快捷方式的功能,与支付宝健康码添加到桌面一样。所以特地研究了下相关产品中该功能的实现方式,如哈罗单车和支付宝。
原理
在 app 里面通过 OpenURL 方式 跳转到Safari 浏览器,打开一个引导页面,然后点击添加到主屏幕,如下图:
哈罗单车的实现
哈罗单车在Safari中展示的是一整张引导图片,为啥这里说一整张图呢,因为支付宝展示的引导页是由多张图片拼接而成。
哈罗单车不同的业务使用快捷方式,需要UI每次做一张引导图,或者做一张通用图片当引导图。
探索支付宝添加桌面快捷方式的实现
- 在关闭网络的情况下,在支付宝健康码中点击"添加到桌面",跳转到Safari浏览器,得到url
https://render.alipay.com/p/s/shortcut/index?appId=20000067&appName=杭州健康码&appIcon=https://gw.alicdn.com/tfs/TB1nUmbzUT1gK0jSZFhXXaAtVXa-1024-1024.png&appUrl=https%3A%2F%2Fh5.dingtalk.com%2FhealthAct%2Findex.html
可以看出url为https://render.alipay.com/p/s/shortcut/index,后面参数有appId,appName,appIcon,appUrl
- 支付宝小程序也同样有添加到桌面的功能,同样的方式获取到小程序跳转到Safari浏览器中的url,这里以"体育服务"小程序为例
https://render.alipay.com/p/s/shortcut/index?appId=2018073060792690&appName=体育服务&appIcon=https://appstoreisvpic.alipayobjects.com/prod/[email protected]
-
我们将支付宝健康码页面的url在mac上的Safari 浏览器打开,查看元素
可以看到页面主要有index.html,index.js,还有几张图片
从这张图我们可以猜到,支付宝是通过html和js将appIcon动态嵌入到上图相应的位置,以此来实现safari中的引导页面。
比较
支付宝的实现方式更加高明,采用动态拼接图片的方式,业务方只需要传入appIcon。
但是哈罗单车主要是靠app客户端实现的,支付宝则是靠Web端来实现。
支付宝总体实现
通过对index.html和index.js的分析,得出支付宝实现方式如下:
app客户端请求站点https://render.alipay.com/p/s/shortcut/index,并将appId,appName,appIcon,appUrl等传递过去。站点下index.html中接收url中携带的参数值,生成对应的base64。
这样app客户端实现起来很简单,只需要打开url并将参数传递过去即可。剩下的交由Web端开发来做。
//支付宝实现应用桌面快捷方式
//url中不含中文时,可以不对url进行unicode转码,使用https://render.alipay.com/p/s/shortcut/index?appId=20000067&appName=123&appIcon=https://gw.alicdn.com/tfs/TB1nUmbzUT1gK0jSZFhXXaAtVXa-1024-1024.png&appUrl=https://Fh5.dingtalk.com/FhealthAct/Findex.html也可以
NSURL *URL = [NSURL URLWithString:@"https://render.alipay.com/p/s/shortcut/index?appId=20000067&appName=123&appIcon=https://gw.alicdn.com/tfs/TB1nUmbzUT1gK0jSZFhXXaAtVXa-1024-1024.png&appUrl=https%3A%2F%2Fh5.dingtalk.com%2FhealthAct%2Findex.html"];
UIApplication *application = [UIApplication sharedApplication];
NSURL *URL = [NSURL URLWithString:urlString];
if (@available(iOS 10.0, *)) {
[application openURL:URL options:@{}
completionHandler:^(BOOL success) {
}];
} else {
[application openURL:URL];
}
但是我身为一个ios开发,可不可以不借助Web端开发,自己单独来实现呢?
如果自己单独实现,需要解决哪些问题呢?
- 首先我从mac端浏览器中可以获取到index.html和index.js和图片等资源文件
- 我们需要将支付宝的index.html文件中原本通过url中获取参数的形式改为app本地替换
步骤
1. 开发引导页面
我们首先在app项目工程的根目录下创建一个文件夹Web,文件夹下存放引导页面
content.html
content.html是拷贝的是支付宝index.html文件,对其做了修改。
- 支付宝的index.html文件通过从浏览器的url中获取参数,通过js函数getQueryParams实现。因为我的参数没有放在URL中,所以通过getQueryParams函数获取到的参数都是空的。可以给appId等参数赋个默认值,这样就实现了本地参数替换。
var query = getQueryParams(location.href);
var { appId = "TransitCodeAppId", appName= "TransitCodeAppTitle", appIcon = "TransitCodeAppIcon", appUrl = "ezvizsaas://123", scheme = "TransitCodeAppScheme" } = query;
修改过后的content.html代码如下:
将其中的"企业萤石云"改成自己的主app名称即可,也可使用字符串进行动态替换。
企业萤石云
代码中包含的一些字符串含义如下:
TransitCodeAppIcon:快捷方式在桌面的图标
TransitCodeAppTitle:快捷方式的名称
TransitCodeAppScheme:跳转页面对应的 scheme,比如 ezvizsaas://web/app?appId=1
通过这几个字符串代替实际内容,就可以做到动态替换。"企业萤石云"替换为自己的主app名称即可。
这里通过 window.navigator.standalone 可以知道引导页是否是全屏展示,如果是全屏那么跳转到 app 对应页面,非全屏则插入具体 HTML 内容,展示引导内容。
index.js
index.js中代码过长,由于对内容长度的限制,会导致无法发布,这里就不贴出来了。
index.js用的是支付宝的代码,其中许多代码是无用的,不过不影响我们的业务,可以不用删减。js中的一些关于"支付宝"的文本可以替换成我们的。
2. 使用 Data URI Scheme 技术将引导页转为一个字符串
代码如下
//iconUrl:桌面图标 appTitle:默认app名称
- (NSString *)oppcreateDesktopWithPreUrl:(NSString *)preUrl iconUrl:(NSString *)iconUrl appTitle:(NSString *)title scheme:(NSString *)scheme {
if ([preUrl length] == 0) {
return nil;
}
NSString *contentHtmlString = [self contentHtmlWithIconImageString:iconUrl title:title appScheme:scheme];
NSData *data = [contentHtmlString dataUsingEncoding:NSUTF8StringEncoding];
contentHtmlString = [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; // base64格式的字符串;
NSString *DataURIString = [NSString stringWithFormat:@"data:text/html;charset=utf-8;base64,%@",contentHtmlString];
NSString *urlString = [NSString stringWithFormat:@"%@%@", preUrl, DataURIString];
return urlString;
}
-(NSString *)contentHtmlWithIconImageString:(NSString *)iconImageString title:(NSString *)title appScheme:(NSString *)scheme{
NSString *contentHtmlPath = [self getcontentHTMLTempletPath];
NSString *contentHtmlString = [NSString stringWithContentsOfFile:contentHtmlPath encoding:NSUTF8StringEncoding error:nil];
/*替换字符串*/
contentHtmlString = [contentHtmlString stringByReplacingOccurrencesOfString:@"TransitCodeAppIcon" withString:iconImageString];
contentHtmlString = [contentHtmlString stringByReplacingOccurrencesOfString:@"TransitCodeAppTitle" withString:title];
contentHtmlString = [contentHtmlString stringByReplacingOccurrencesOfString:@"TransitCodeAppScheme" withString:scheme];
return contentHtmlString;
}
- (NSString *)getcontentHTMLTempletPath{
NSString * path = [[NSBundle mainBundle] pathForResource:@"content" ofType:@"html"];
return path;
}
Data URI Scheme 技术就是将一个文件,图片或者HTML文件等等,通过 Base64 加密等转为字符串放到 HTML 里面直接加载,这样就不用请求服务器了。这里我们需要将上面介绍的本地的引导 HTML 页面转为一个字符串,后面要将这个字符串拼到服务器HTML url 后面。
看代码可以知道,通过 getcontentHTMLTempletPath 方法拿到本地 HTML 文件路径,然后将里面内容进行替换为我们应用的快捷方式相关内容。然后将 HTML 内容转为 base64 编码。最后通过将 base64 编码按照特定格式拼接即可,这里是
[NSString stringWithFormat:@"data:text/html;charset=utf-8;base64,%@",contentHtmlString];以 data:text/html;charset=utf-8;base64, 开头,后面我们可以看到存储的时候也是保存的这个。
3. 打开服务器 HTML 页,用本地引导页替换
用上面生成的字符串拼到服务器 HTML 页面url (这里我是直接将 HTML 文件发给Web端同事,放到 Web网站上面然后拿到链接)后面,代码如下
//下面是添加快捷方式到桌面的相关代码
- (void)addShortcutToDesk {
NSString *baseUrl = @"https://www.baidu.com"; //这里将https://www.baidu.com替换为你自己的shortcut-middle.html所在的Web服务器地址
NSString *preUrl = [NSString stringWithFormat:@"%@/shortcut-middle.html",baseUrl];
preUrl = [NSString stringWithFormat:@"%@?dataurl=", preUrl];
NSString *title = [self.webAppParams objectForKey:@"appName"];
NSString *scheme = [NSString stringWithFormat:@"ezvizsaas://web/app?appId=%ld",self.webAppId];
NSString *iconUrl = [self.webAppParams objectForKey:@"appLogo"];
NSString *urlString = [self oppcreateDesktopWithPreUrl:preUrl iconUrl:iconUrl appTitle:title scheme:scheme];
UIApplication *application = [UIApplication sharedApplication];
NSURL *URL = [NSURL URLWithString:urlString];
if (@available(iOS 10.0, *)) {
[application openURL:URL options:@{}
completionHandler:^(BOOL success) {
}];
} else {
[application openURL:URL];
}
}
这里服务器保存的 HTML页面shortcut-middle.html很简单,加载后主要就是通过上面拼接的链接获取本地引导页内容,然后加载引导页,shortcut-middle.html代码如下
通过 location.search 方法可以获取到拼接好的url内容,然后拿到我们拼上去的内容,使用 window.location.replace 方法来重新进行内容替换,就可以展示我们本地的引导页了。此时展示就是非全屏展示,跟从快捷键打开不一样。
可能遇到的问题
- 在Safari中出现如下错误提示 414 Request-URI Too Large
这是因为我们的url超过了nginx 服务器的限制,找Web端开发人员设置下nginx 服务器的配置即可。
参考https://blog.csdn.net/qq_41198398/article/details/83618204
- 添加到桌面的图标有黑边
这是因为我们传入的appIcon图标有圆角,appIcon用大图512x512或1024x1024,不要圆角
参考资料
- 哈罗单车乘车码添加桌面快捷方式
https://www.jianshu.com/p/15e36a3bd22c - 支付宝健康码和小程序添加桌面快捷方式