
终于把人人商城打包好了
1、支付宝原生支付,微信原生支付
2、分享微信,QQ
3、微信登录
4、退出App
5、清理App缓存
6、个推推送(订单推送)
有需要沟通的 M我把 vx 185341954
1、支付宝原生支付,微信原生支付
2、分享微信,QQ
3、微信登录
4、退出App
5、清理App缓存
6、个推推送(订单推送)
有需要沟通的 M我把 vx 185341954

Android平台 storage性能优化说明
HBuilderX2.6.6+起,Android平台对App本地storage数据存储进行了性能优化,包括plus.storage和uni的storage相关api,主要包括以下改进:
- 数据存储方式优化
之前的storage数据存储到Android系统的SharedPreferences
中,现在修改为存储到数据库文件
中。
SharedPreferences
是 Android 平台为应用开发者提供的一个轻量级的存储辅助类,不适合存储大量的数据,当数据量过大时会影响性能甚至引发ANR。
数据库文件
存储则可以更好的支持大量数据存储,但需要注意JS与原生通讯时传输数据时也存在性能限制,因此不要一次存储大量的数据,建议每次存储数据不要超过100K。 - 新增异步操作接口
原来5+ API中plus.storage只提供同步操作接口,uni-app中的异步接口在App端也是封装同步接口实现的,之前并非真正异步。
新版本已提供异步接口读取、保存数据,避免同步接口阻塞JS。uni-app中的异步接口也调整为真正的异步操作实现。
通过对比测试,以上优化单次读取速度提升10%
,并发300次读取速度提升70%
。
应用升级向下兼容处理
为了确保应用的新版平滑兼容,当基于新版打包的App升级覆盖老版本App时,会在应用启动时自动将原来存储在SharedPreferences
中的数据迁移到数据库文件中,开发者不需要做特殊处理就可以读取到老版本保存的数据。
如果老版App在手机端已经保存了大量数据,覆盖升级新版后,第一次运行新版会因为迁移数据而导致splash界面显示时间稍微变长一些。
注意事项
SharedPreferences
方式存储的数据向数据库文件
存储的升级,是不可逆的过程。
举个极端例子,开发者已有app版本1.0,并且已经在手机端存储了storage数据,然后开发者使用HBuilderX2.6.6+打包生成2.0的app,新app覆盖安装1.0版后,将storage数据从SharedPreferences
迁移到了数据库文件
。接着开发者又回退了HBuilderX版本,使用HBuilderX2.6.6-的版本,打包生成了3.0app,那么这个3.0app覆盖安装到手机上后,使用plus.storage和uni的storage相关api将无法读取历史数据,相关api会继续操作SharedPreferences
方式存储的数据。
plus.storage新增异步接口的清单如下:
- plus.storage.clearAsync
异步清除存储数据 - plus.storage.getAllKeysAsync
异步获取所有键名 - plus.storage.getItemAsync
异步获取存储的键值 - plus.storage.setItemAsync
异步存储键值 - plus.storage.removeItemAsync
异步删除键值
uni的storage操作api无变化,见:https://uniapp.dcloud.io/api/storage/storage?id=setstorage
HBuilderX2.6.6+起,Android平台对App本地storage数据存储进行了性能优化,包括plus.storage和uni的storage相关api,主要包括以下改进:
- 数据存储方式优化
之前的storage数据存储到Android系统的SharedPreferences
中,现在修改为存储到数据库文件
中。
SharedPreferences
是 Android 平台为应用开发者提供的一个轻量级的存储辅助类,不适合存储大量的数据,当数据量过大时会影响性能甚至引发ANR。
数据库文件
存储则可以更好的支持大量数据存储,但需要注意JS与原生通讯时传输数据时也存在性能限制,因此不要一次存储大量的数据,建议每次存储数据不要超过100K。 - 新增异步操作接口
原来5+ API中plus.storage只提供同步操作接口,uni-app中的异步接口在App端也是封装同步接口实现的,之前并非真正异步。
新版本已提供异步接口读取、保存数据,避免同步接口阻塞JS。uni-app中的异步接口也调整为真正的异步操作实现。
通过对比测试,以上优化单次读取速度提升10%
,并发300次读取速度提升70%
。
应用升级向下兼容处理
为了确保应用的新版平滑兼容,当基于新版打包的App升级覆盖老版本App时,会在应用启动时自动将原来存储在SharedPreferences
中的数据迁移到数据库文件中,开发者不需要做特殊处理就可以读取到老版本保存的数据。
如果老版App在手机端已经保存了大量数据,覆盖升级新版后,第一次运行新版会因为迁移数据而导致splash界面显示时间稍微变长一些。
注意事项
SharedPreferences
方式存储的数据向数据库文件
存储的升级,是不可逆的过程。
举个极端例子,开发者已有app版本1.0,并且已经在手机端存储了storage数据,然后开发者使用HBuilderX2.6.6+打包生成2.0的app,新app覆盖安装1.0版后,将storage数据从SharedPreferences
迁移到了数据库文件
。接着开发者又回退了HBuilderX版本,使用HBuilderX2.6.6-的版本,打包生成了3.0app,那么这个3.0app覆盖安装到手机上后,使用plus.storage和uni的storage相关api将无法读取历史数据,相关api会继续操作SharedPreferences
方式存储的数据。
plus.storage新增异步接口的清单如下:
- plus.storage.clearAsync
异步清除存储数据 - plus.storage.getAllKeysAsync
异步获取所有键名 - plus.storage.getItemAsync
异步获取存储的键值 - plus.storage.setItemAsync
异步存储键值 - plus.storage.removeItemAsync
异步删除键值
uni的storage操作api无变化,见:https://uniapp.dcloud.io/api/storage/storage?id=setstorage
收起阅读 »
HBuilderX 使用eslint实时校验、自动修复代码错误(适用于HBuilderX 2.6.8+)
HBuilderX 2.6.8+版本起,新增eslint 实时校验、自动修复错误的功能。注意:此文不适用于2.6.8之前的版本
插件下载地址
eslint-js插件下载地址
eslint-vue插件下载地址
1. eslint 文件保存,实时校验、自动修复错误功能说明
- 使用此功能,必须安装
eslint-js
和eslint-vue
插件。(菜单【工具】【插件安装】) vue-cli
项目,需要安装eslint库,并配置eslint规则.- 若满足上述条件,当编写完代码,保存时,若代码中存在错误,自动修复;
2. 插件设置
2.6.11版本,支持自定义配置:
保存时自动修复
和启用实时校验
;见下图
特别说明: 实时校验功能,默认未开启,需要手动开启此功能

3. 特别说明
特别说明: eslint自动修复功能,并不能修复所有的语法错误。
比如定义了某个变量,但未使用,eslint校验保存,自动修复功能并不能修复此类错误。
4. 普通项目:eslint规则配置
点击菜单【工具】【插件配置】【eslint-js】,编辑.eslintrc.js
文件
eslint规则:https://eslint.org/docs/rules/
.eslintrc.js配置文件示例
module.exports = {
"plugins": [
"html"
],
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
},
"allowImportExportEverywhere": false
},
rules: {
"no-alert": 0,
"semi": [2, "always"],
"no-multi-spaces": "error",
"quotes": ["error", "single"]
}
}
示例:使用eslint, 删除多余的空格
5. vue-cli项目:eslint安装、配置
$ npm install --save eslint eslint-plugin-vue eslint-plugin-html eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-promise eslint-plugin-standard
安装完成后,在vue-cli项目根目录,创建.eslintrc.js
文件
备注:(注意:项目下eslint规则
会覆盖HBuilderX编辑器eslint插件中的规则
)
eslint-plugin-vue配置文件与规则:eslint-plugin-vue官方教程
.eslintrc.js配置文件示例
module.exports = {
extends: [
'plugin:vue/recommended'
],
rules: {
"no-alert": 0,
"no-multi-spaces": "error", // 禁止多个空格
"semi": [2, "always"] ,// 自动补充分号
"quotes": ["error", "single"] // 使用单引号
}
}
示例:使用eslint, 自动补充分号
6. 以uni-app项目为例,配置eslint规则,校验vue文件
特别说明:
- vue文件,校验规则,需要从
eslint-vue
插件中配置。 - 菜单【工具】【插件配置】【eslint-vue】【.eslintrc.js】,编辑
.eslintrc.js
文件
7. vue-cli 项目demo
附件中的zip包,为vue-cli项目demo。因为node_modules太大,所以未包含node_modules。解压zip后,请执行npm install安装node_modules
HBuilderX 2.6.8+版本起,新增eslint 实时校验、自动修复错误的功能。注意:此文不适用于2.6.8之前的版本
插件下载地址
eslint-js插件下载地址
eslint-vue插件下载地址
1. eslint 文件保存,实时校验、自动修复错误功能说明
- 使用此功能,必须安装
eslint-js
和eslint-vue
插件。(菜单【工具】【插件安装】) vue-cli
项目,需要安装eslint库,并配置eslint规则.- 若满足上述条件,当编写完代码,保存时,若代码中存在错误,自动修复;
2. 插件设置
2.6.11版本,支持自定义配置:
保存时自动修复
和启用实时校验
;见下图
特别说明: 实时校验功能,默认未开启,需要手动开启此功能
3. 特别说明
特别说明: eslint自动修复功能,并不能修复所有的语法错误。
比如定义了某个变量,但未使用,eslint校验保存,自动修复功能并不能修复此类错误。
4. 普通项目:eslint规则配置
点击菜单【工具】【插件配置】【eslint-js】,编辑.eslintrc.js
文件
eslint规则:https://eslint.org/docs/rules/
.eslintrc.js配置文件示例
module.exports = {
"plugins": [
"html"
],
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
},
"allowImportExportEverywhere": false
},
rules: {
"no-alert": 0,
"semi": [2, "always"],
"no-multi-spaces": "error",
"quotes": ["error", "single"]
}
}
示例:使用eslint, 删除多余的空格
5. vue-cli项目:eslint安装、配置
$ npm install --save eslint eslint-plugin-vue eslint-plugin-html eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-promise eslint-plugin-standard
安装完成后,在vue-cli项目根目录,创建.eslintrc.js
文件
备注:(注意:项目下eslint规则
会覆盖HBuilderX编辑器eslint插件中的规则
)
eslint-plugin-vue配置文件与规则:eslint-plugin-vue官方教程
.eslintrc.js配置文件示例
module.exports = {
extends: [
'plugin:vue/recommended'
],
rules: {
"no-alert": 0,
"no-multi-spaces": "error", // 禁止多个空格
"semi": [2, "always"] ,// 自动补充分号
"quotes": ["error", "single"] // 使用单引号
}
}
示例:使用eslint, 自动补充分号
6. 以uni-app项目为例,配置eslint规则,校验vue文件
特别说明:
- vue文件,校验规则,需要从
eslint-vue
插件中配置。 - 菜单【工具】【插件配置】【eslint-vue】【.eslintrc.js】,编辑
.eslintrc.js
文件
7. vue-cli 项目demo
附件中的zip包,为vue-cli项目demo。因为node_modules太大,所以未包含node_modules。解压zip后,请执行npm install安装node_modules
收起阅读 »
iOS uni小程序SDK API 参考手册
DCUniMPSDKEngine 类
初始化 SDK 全局环境
/// @param options 初始化参数
+ (void)initSDKEnvironmentWihtLaunchOptions:(NSDictionary *)options;
初始化 sdk engine,并设置启动参数,建议在 application:didFinishLaunchingWithOptions 方法中添加
示例
- (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 initSDKEnvironmentWihtLaunchOptions:options];
return YES;
}
App系统生命周期事件方法
App 系统生命周期方法中调用 SDK 相关方法
示例
- (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];
}
App系统事件回调方法
可根据项目需求,选择实现以下方法
示例
#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;
}
#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];
}
判断应用资源是否已经部署
+ (BOOL)isExistsApp:(NSString *)appid;
将wgt应用资源包部署到运行路径中
/// @param appid appid
/// @param wgtPath wgt应用资源包路径
+ (BOOL)releaseAppResourceToRunPathWithAppid:(NSString *)appid
resourceFilePath:(NSString *)wgtPath;
示例
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(@"应用资源文件部署成功");
}
}
打开小程序应用
/// @param appid appid
/// @param arguments 启动参数(可以在小程序中通过 plus.runtime.arguments 获取此参数)
/// @param redirectPath 启动后直接打开的页面路径 例:"pages/component/view/view?a=1&b=2"
+ (void)openApp:(NSString *)appid
arguments:(NSDictionary * _Nullable)arguments
redirectPath:(NSString * _Nullable)redirectPath;
获取应用资源运行路径
+ (NSString *)getAppRunPathWithAppid:(NSString *)appid;
<a id="getUniMPVersionInfo"></a>
获取已经部署的小程序应用资源版本信息
+ (NSDictionary *)getUniMPVersionInfoWithAppid:(NSString *)appid;
注:返回数据如下对应小程序应用中 manifest.json 配置的信息
{
"name": "1.0.0", // 应用版本名称
"code": 100 // 应用版本号
}
关闭当前小程序应用
+ (void)closeUniMP;
获取当前运行的小程序appid
+ (NSString *)getActiveUniMPAppid;
<a id="getCurrentPageUrl"></a>
获取当前显示小程序页面的直达链接url
用于打开小程序直达二级页面
+ (NSString *)getCurrentPageUrl;
DCUniMPSDKEngine 类
初始化 SDK 全局环境
/// @param options 初始化参数
+ (void)initSDKEnvironmentWihtLaunchOptions:(NSDictionary *)options;
初始化 sdk engine,并设置启动参数,建议在 application:didFinishLaunchingWithOptions 方法中添加
示例
- (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 initSDKEnvironmentWihtLaunchOptions:options];
return YES;
}
App系统生命周期事件方法
App 系统生命周期方法中调用 SDK 相关方法
示例
- (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];
}
App系统事件回调方法
可根据项目需求,选择实现以下方法
示例
#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;
}
#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];
}
判断应用资源是否已经部署
+ (BOOL)isExistsApp:(NSString *)appid;
将wgt应用资源包部署到运行路径中
/// @param appid appid
/// @param wgtPath wgt应用资源包路径
+ (BOOL)releaseAppResourceToRunPathWithAppid:(NSString *)appid
resourceFilePath:(NSString *)wgtPath;
示例
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(@"应用资源文件部署成功");
}
}
打开小程序应用
/// @param appid appid
/// @param arguments 启动参数(可以在小程序中通过 plus.runtime.arguments 获取此参数)
/// @param redirectPath 启动后直接打开的页面路径 例:"pages/component/view/view?a=1&b=2"
+ (void)openApp:(NSString *)appid
arguments:(NSDictionary * _Nullable)arguments
redirectPath:(NSString * _Nullable)redirectPath;
获取应用资源运行路径
+ (NSString *)getAppRunPathWithAppid:(NSString *)appid;
<a id="getUniMPVersionInfo"></a>
获取已经部署的小程序应用资源版本信息
+ (NSDictionary *)getUniMPVersionInfoWithAppid:(NSString *)appid;
注:返回数据如下对应小程序应用中 manifest.json 配置的信息
{
"name": "1.0.0", // 应用版本名称
"code": 100 // 应用版本号
}
关闭当前小程序应用
+ (void)closeUniMP;
获取当前运行的小程序appid
+ (NSString *)getActiveUniMPAppid;
<a id="getCurrentPageUrl"></a>
获取当前显示小程序页面的直达链接url
用于打开小程序直达二级页面
+ (NSString *)getCurrentPageUrl;
收起阅读 »

文件下载保存, 遇到uni.downloadFile的坑
uni.downloadFile({
//https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top-e3b63a0b1b.png
url: 'http://music.163.com/song/media/outer/url?id=65538.mp3',
success: (res) => {
if (res.statusCode === 200) {
console.log('下载成功');
}
console.log(res.tempFilePath);
uni.saveFile({
tempFilePath: res.tempFilePath,
complete(res) {
console.log(res)
}
});
}
});
按官网api通过uni.downloadFile,获得tempFilePath 临时文件路径,再调用uni.saveFiled保存文件。测试发现几个问题:
-
下载图片(小文件),下载成功后调saveFiled 是可以保存成功的。但是换成MP3文件(大文件),下载成功后,保存报错提示文件不存在;
。这个问题不知是BUG,还是说这种方式就不支持大文件。
-
uni.downloadFile 不支持后台下载,手机黑屏就暂停下载了。
现在解决方案 改用H5+api
不多BB直接看代码:
//查看已下载的文件
function checkDownload(){
plus.io.requestFileSystem( plus.io.PUBLIC_DOWNLOADS, function(fs){
var directoryReader = fs.root.createReader();
directoryReader.readEntries( function( entries ){
var i;
for( i=0; i < entries.length; i++ ) {
console.log( entries[i].name );
entries[i].name = i
}
}, function ( e ) {
console.log( "Read entries failed: " + e.message );
});
});
}
// 创建下载任务
function createDownload() {
var dtask = plus.downloader.createDownload("https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top-e3b63a0b1b.png", {}, function(d, status){
// 下载完成 下载的文件会保存在 PUBLIC_DOWNLOADS 目录下,只要不主动删除都会存在
if(status == 200){
console.log("Download success: ");
console.log(d);
checkDownload()
} else {
console.log("Download failed: " + status);
}
});
;
dtask.start();
}
createDownload()
解决了问题1, 下载文件, 查看已下载的文件。
这个方式依然不能后台下载。
还有不知怎么修改下载的文件名
uni.downloadFile({
//https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top-e3b63a0b1b.png
url: 'http://music.163.com/song/media/outer/url?id=65538.mp3',
success: (res) => {
if (res.statusCode === 200) {
console.log('下载成功');
}
console.log(res.tempFilePath);
uni.saveFile({
tempFilePath: res.tempFilePath,
complete(res) {
console.log(res)
}
});
}
});
按官网api通过uni.downloadFile,获得tempFilePath 临时文件路径,再调用uni.saveFiled保存文件。测试发现几个问题:
-
下载图片(小文件),下载成功后调saveFiled 是可以保存成功的。但是换成MP3文件(大文件),下载成功后,保存报错提示文件不存在;
。这个问题不知是BUG,还是说这种方式就不支持大文件。
-
uni.downloadFile 不支持后台下载,手机黑屏就暂停下载了。
现在解决方案 改用H5+api
不多BB直接看代码:
//查看已下载的文件
function checkDownload(){
plus.io.requestFileSystem( plus.io.PUBLIC_DOWNLOADS, function(fs){
var directoryReader = fs.root.createReader();
directoryReader.readEntries( function( entries ){
var i;
for( i=0; i < entries.length; i++ ) {
console.log( entries[i].name );
entries[i].name = i
}
}, function ( e ) {
console.log( "Read entries failed: " + e.message );
});
});
}
// 创建下载任务
function createDownload() {
var dtask = plus.downloader.createDownload("https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top-e3b63a0b1b.png", {}, function(d, status){
// 下载完成 下载的文件会保存在 PUBLIC_DOWNLOADS 目录下,只要不主动删除都会存在
if(status == 200){
console.log("Download success: ");
console.log(d);
checkDownload()
} else {
console.log("Download failed: " + status);
}
});
;
dtask.start();
}
createDownload()
解决了问题1, 下载文件, 查看已下载的文件。
这个方式依然不能后台下载。
还有不知怎么修改下载的文件名 收起阅读 »

uni-app H5端 “网络不给力” 排查日记
前述
用户访问时莫名奇妙的出现“网络不给力”(连接服务器超时)的提示,可是此时用工具测试网络速度明明很给力。开发人员排查时却无法复现问题,于是开始认为是框架有问题。
作为框架的维护人员经过排查并未发现框架有相关问题,联系多位开发人员协助排查,终于总结出如下结论:
解决办法
太长不看版:使用 CDN、https 。
网络不给力
用户出现问题的时候,开发人员首先怀疑的就是这个内置的“网络不给力”错误页面,开始想办法去掉这个错误提示页面。
首先就要说一下为什么 SPA(单页应用) 都必须有这个页面,普通的 MPA(多页应用)其页面跳转(从一个html跳转到另外一个html)是浏览器负责的,页面加载失败的时候会显示浏览器的失败提示,而 SPA 是使用 ajax 异步加载页面,所以需要自己来判断页面是否加载成功,以及在加载失败的时候显示提示。如果去掉这个提示页面,仅仅是相当于掩耳盗铃,并不能解决问题。
加载超时(情况一)
之前框架默认的加载超时时间是3秒(后续才增大了默认超时时间),是相信运维人员都了解CDN的,一般的商业项目部署 H5 离不开 CDN ,一方面是为了用户体验,一方面是为了运营成本。
经过排查大部分页面加载慢导致超时的用户,都有一个特点,将资源直接部署在了自己服务器供用户访问。
服务端如果采用5兆带宽,同时10个用户访问的情况下,平均每个用户分得0.5兆,其下载速度约为0.06兆每秒,加载0.3兆的文件需要5秒,远超了默认的超时时间,而且这只是理论计算,实际带宽的分配并非均匀,有的用户分得的更小,加载的时间更长。另外服务器机房和网络线路固定,不同地区和网络运营商的用户访问体验不一致。
对此的解决办法有两种:
- 配置页面加载超时时间(新版的HBuilderX已经增大了默认超时时间):相关文档,优点:方便快捷,只需修改配置重新发布即可;缺点:并不能真正改善用户体验,使用服务器硬扛流量还可能会给服务器上的其他业务带来影响。
- 使用 CDN ,优点:相比增加服务器带宽成本更低,体验更好。
加载出错(情况二)
即使增加了页面的超时时间,仍然有部分用户访问页面时(使用http)出现错误提示,而且并未达到配置的超时时间(有的是切换页面瞬间出现),甚至刷新页面仍然无济于事。开发者调试的时候却始终无法复现。
以下是开发者让用户协助调试提供的截图(开发者未使用CDN为了避免各位访问测试造成压力,对域名进行了打码):
从图中可以看出加载此页面的js文件报错了,此时让用户直接访问这个报错的js文件地址,出现如下内容:
开发者一眼就看出js文件的内容不对,并不是页面真正的js文件,应该是遇到了网络劫持。网上搜索内容中出现的域名,发现中招的人不少:
一般办公使用的商用网络很少有劫持问题,而民用的网络层层转包不免有流氓运营商从中作梗,所以用户会出现问题,而开发者难以复现。
针对此问题,简易便捷解决办法就是升级为 https。
还是加载出错(情况三)
有开发者已经升级到了https,已经解决了网络劫持的问题,但是过了一段时间更新后,仍然有部分用户出现了“网络不给力”的问题。调试发现报错的js文件的文件名和线上的文件名不一致(主要是hash部分不同),是旧版本的文件名。说明html使用了旧版的缓存,请求的页面js文件是旧的,这个问题一般出现在微信内置浏览器中。
百度一下,发现类似的问题很多:百度:微信html缓存
搜到的处理方法基本是修改html的响应头,禁用html的缓存(不必禁用js、css等资源的缓存)。
实际这个问题有两种处理方式:
- 禁用html缓存,让用户访问到新版
- 每次更新时不删除旧的js、css资源,让使用旧版的用户也能继续访问
已使用CDN的用户一般未发现这个问题,因为CDN缓存了旧版的文件,即使服务器上已经删除了,CDN仍然能访问到。
结语
至此 “网络不给力” 问题排查告一段落,结论就是 CDN 和 https ,感谢一直配合调查测试的开发者,如果还有谁遇到此外的情况,请私信或者留言联系,官方会协助排查。
前述
用户访问时莫名奇妙的出现“网络不给力”(连接服务器超时)的提示,可是此时用工具测试网络速度明明很给力。开发人员排查时却无法复现问题,于是开始认为是框架有问题。
作为框架的维护人员经过排查并未发现框架有相关问题,联系多位开发人员协助排查,终于总结出如下结论:
解决办法
太长不看版:使用 CDN、https 。
网络不给力
用户出现问题的时候,开发人员首先怀疑的就是这个内置的“网络不给力”错误页面,开始想办法去掉这个错误提示页面。
首先就要说一下为什么 SPA(单页应用) 都必须有这个页面,普通的 MPA(多页应用)其页面跳转(从一个html跳转到另外一个html)是浏览器负责的,页面加载失败的时候会显示浏览器的失败提示,而 SPA 是使用 ajax 异步加载页面,所以需要自己来判断页面是否加载成功,以及在加载失败的时候显示提示。如果去掉这个提示页面,仅仅是相当于掩耳盗铃,并不能解决问题。
加载超时(情况一)
之前框架默认的加载超时时间是3秒(后续才增大了默认超时时间),是相信运维人员都了解CDN的,一般的商业项目部署 H5 离不开 CDN ,一方面是为了用户体验,一方面是为了运营成本。
经过排查大部分页面加载慢导致超时的用户,都有一个特点,将资源直接部署在了自己服务器供用户访问。
服务端如果采用5兆带宽,同时10个用户访问的情况下,平均每个用户分得0.5兆,其下载速度约为0.06兆每秒,加载0.3兆的文件需要5秒,远超了默认的超时时间,而且这只是理论计算,实际带宽的分配并非均匀,有的用户分得的更小,加载的时间更长。另外服务器机房和网络线路固定,不同地区和网络运营商的用户访问体验不一致。
对此的解决办法有两种:
- 配置页面加载超时时间(新版的HBuilderX已经增大了默认超时时间):相关文档,优点:方便快捷,只需修改配置重新发布即可;缺点:并不能真正改善用户体验,使用服务器硬扛流量还可能会给服务器上的其他业务带来影响。
- 使用 CDN ,优点:相比增加服务器带宽成本更低,体验更好。
加载出错(情况二)
即使增加了页面的超时时间,仍然有部分用户访问页面时(使用http)出现错误提示,而且并未达到配置的超时时间(有的是切换页面瞬间出现),甚至刷新页面仍然无济于事。开发者调试的时候却始终无法复现。
以下是开发者让用户协助调试提供的截图(开发者未使用CDN为了避免各位访问测试造成压力,对域名进行了打码):
从图中可以看出加载此页面的js文件报错了,此时让用户直接访问这个报错的js文件地址,出现如下内容:
开发者一眼就看出js文件的内容不对,并不是页面真正的js文件,应该是遇到了网络劫持。网上搜索内容中出现的域名,发现中招的人不少:
一般办公使用的商用网络很少有劫持问题,而民用的网络层层转包不免有流氓运营商从中作梗,所以用户会出现问题,而开发者难以复现。
针对此问题,简易便捷解决办法就是升级为 https。
还是加载出错(情况三)
有开发者已经升级到了https,已经解决了网络劫持的问题,但是过了一段时间更新后,仍然有部分用户出现了“网络不给力”的问题。调试发现报错的js文件的文件名和线上的文件名不一致(主要是hash部分不同),是旧版本的文件名。说明html使用了旧版的缓存,请求的页面js文件是旧的,这个问题一般出现在微信内置浏览器中。
百度一下,发现类似的问题很多:百度:微信html缓存
搜到的处理方法基本是修改html的响应头,禁用html的缓存(不必禁用js、css等资源的缓存)。
实际这个问题有两种处理方式:
- 禁用html缓存,让用户访问到新版
- 每次更新时不删除旧的js、css资源,让使用旧版的用户也能继续访问
已使用CDN的用户一般未发现这个问题,因为CDN缓存了旧版的文件,即使服务器上已经删除了,CDN仍然能访问到。
结语
至此 “网络不给力” 问题排查告一段落,结论就是 CDN 和 https ,感谢一直配合调查测试的开发者,如果还有谁遇到此外的情况,请私信或者留言联系,官方会协助排查。
收起阅读 »
发现一个subNVue的隐藏功能,官方居然没文档介绍
发现一个subNVue的隐藏功能,官方居然没文档介绍,那就是subNVue.close() ,不知道参数都哪些,今天实验可用。希望尽快给我们文档介绍。
发现一个subNVue的隐藏功能,官方居然没文档介绍,那就是subNVue.close() ,不知道参数都哪些,今天实验可用。希望尽快给我们文档介绍。

解决uni-app编译后vendor.js文件过大
背景与现象
- 将一个当前只有简单功能的H5项目(通过vue-cli 3 创建) 迁移为uni-app版本,需要支持输出为QQ小程序、H5,在QQ小程序开发者工具中,发现无法生成预览和真机调试,原因是代码包超过2M,经过分析,发现编译后代码中,最大的是:
common/vendor.js
,一些处理后仍有2.5M。打包生产版本分析,也是同样的问题。 - 项目通过vue-cli命令行创建,因此以下涉及示例的,都以此为准,使用HBuilderX开发的,麻烦自行转换操作。
解决方法
- 开启运行时压缩
这个方法测试了,没看出有什么帮助。
- 分包优化
这个方法更多地是对于页面过多或static图片资源过多的情况有用。此项目也进行了分包,但这个并未解决打包后vendor过大的问题。
以上2个方法,为uni官方建议的处理vendor过大的方法,见文档-介绍-uni-app 跨端开发注意事项-vendor过大的处理方式
- Bug:分包资源被打包到主包而导致的vendor过大
这个问题没有遇到,看起来是曾经版本出现过,但新版本已修复,若是这个问题导致的,则可参考:issue #649,question #72577
- 其他的一些处理方式
看到的一篇文章,虽然我的项目中不是这些原因,但这些方法是需要考虑的:小程序包大小优化(uni-app)
- 开启生产环境gzip,vendor.js从2.5M减少到440k
如何开启,使用compression-webpack-plugin
vue.config.js:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']
configureWebpack: {
plugins: [
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp('\\.(' productionGzipExtensions.join('|') ')$'),//匹配文件名
threshold: 10240,//对10K以上的数据进行压缩
minRatio: 0.8,
deleteOriginalAssets:false,//是否删除源文件
})
]}
}
文件分析
使用 webpackBundleAnalyzer,可以帮助分析文件大小。
vue.config.js:
pluginOptions: {
webpackBundleAnalyzer: {
openAnalyzer: process.env.NODE_ENV === 'production'
}
},
编译后,会同时带一份报告,可查看 stat, parsed, gzip 三种状态的文件大小。
背景与现象
- 将一个当前只有简单功能的H5项目(通过vue-cli 3 创建) 迁移为uni-app版本,需要支持输出为QQ小程序、H5,在QQ小程序开发者工具中,发现无法生成预览和真机调试,原因是代码包超过2M,经过分析,发现编译后代码中,最大的是:
common/vendor.js
,一些处理后仍有2.5M。打包生产版本分析,也是同样的问题。 - 项目通过vue-cli命令行创建,因此以下涉及示例的,都以此为准,使用HBuilderX开发的,麻烦自行转换操作。
解决方法
- 开启运行时压缩
这个方法测试了,没看出有什么帮助。
- 分包优化
这个方法更多地是对于页面过多或static图片资源过多的情况有用。此项目也进行了分包,但这个并未解决打包后vendor过大的问题。
以上2个方法,为uni官方建议的处理vendor过大的方法,见文档-介绍-uni-app 跨端开发注意事项-vendor过大的处理方式
- Bug:分包资源被打包到主包而导致的vendor过大
这个问题没有遇到,看起来是曾经版本出现过,但新版本已修复,若是这个问题导致的,则可参考:issue #649,question #72577
- 其他的一些处理方式
看到的一篇文章,虽然我的项目中不是这些原因,但这些方法是需要考虑的:小程序包大小优化(uni-app)
- 开启生产环境gzip,vendor.js从2.5M减少到440k
如何开启,使用compression-webpack-plugin
vue.config.js:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']
configureWebpack: {
plugins: [
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp('\\.(' productionGzipExtensions.join('|') ')$'),//匹配文件名
threshold: 10240,//对10K以上的数据进行压缩
minRatio: 0.8,
deleteOriginalAssets:false,//是否删除源文件
})
]}
}
文件分析
使用 webpackBundleAnalyzer,可以帮助分析文件大小。
vue.config.js:
pluginOptions: {
webpackBundleAnalyzer: {
openAnalyzer: process.env.NODE_ENV === 'production'
}
},
编译后,会同时带一份报告,可查看 stat, parsed, gzip 三种状态的文件大小。
收起阅读 »
IOS离线打包微信分享发生多次二次跳转行为
如果确认配置都正确,还是发生多次二次跳转,请到微信下载最新的sdk,libWeChatSDK.a这个文件替换原来的,就可以了.
如果确认配置都正确,还是发生多次二次跳转,请到微信下载最新的sdk,libWeChatSDK.a这个文件替换原来的,就可以了.

分享案例,欢迎讨论
下载地址:
安卓(IOS地址) https://www.dfs168.com/market/viewapp.html?id=503
苹果: https://apps.apple.com/cn/app/id1489907205
H5地址:
http://wechat.dfs168.com/
微信小程序
(微信搜索:大丰收农资优选)
下载地址:
安卓(IOS地址) https://www.dfs168.com/market/viewapp.html?id=503
苹果: https://apps.apple.com/cn/app/id1489907205
H5地址:
http://wechat.dfs168.com/
微信小程序
(微信搜索:大丰收农资优选)