HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

沐融天津海外研发中心成立,招聘Uniapp高手,快到碗里来!!!欢迎投递简历到zhaopin@murongtech.com。

招聘

北京沐融信息科技股份有限公司是全球领先的数字金融IT解决方案提供商,专注于融合互联网技术,为银行、保险、基金
、证券、支付机构、企业金融等金融行业客户提供丰富的软件产品及解决方案。公司总部位于中国北京,在上海、广州、
深圳、天津、肯尼亚等地设有分支机构。

在肯尼亚我们正在为客户打造全业务场景的支付app,对标支付宝,建立小程序生态;欢迎有志于此的朋友加入,一起打造非洲的支付宝;现需要招聘以下人员:

职位:前端开发工程师(中高级)、前端开发经理

职责描述:
1、在uni-app框架下,进行移动多端(iOS、Android、微信小程序)开发;
2、根据产品经理的需求和UI设计进行页面开发、功能开发;
3、负责公司APP的开发、迭代与优化;
4、参与APP研发技术的积累、学习、实践工作;
5、负责公司APP团队人员培养,队伍建设、技术路线发展等(管理岗)

任职要求:
1、3年以上前端开发工作经验,至少两个uniapp项目开发经验;
2、精通前端基本技术,包括HTML、CSS、Javacript 等;
3、精通JSON、XML等通信格式以及基于AJAX请求实现与后台数据交互;
4、熟悉微信生态及微信小程序生态,有完整的微信小程序项目经验;
5、熟悉使用HBuilder IDE编辑器进行开发,并完成打包发布安卓、ios版本app;
6、精通Vue、uni-app框架应用,并能运用uni-app框架完成移动端及小程序开发;
7、大专及以上学历,责任心强,有团队精神,学习能力强

工作地点:天津 河东区远洋国际中心A座29层
简历请投递:zhaopin@murongtech.com

继续阅读 »

北京沐融信息科技股份有限公司是全球领先的数字金融IT解决方案提供商,专注于融合互联网技术,为银行、保险、基金
、证券、支付机构、企业金融等金融行业客户提供丰富的软件产品及解决方案。公司总部位于中国北京,在上海、广州、
深圳、天津、肯尼亚等地设有分支机构。

在肯尼亚我们正在为客户打造全业务场景的支付app,对标支付宝,建立小程序生态;欢迎有志于此的朋友加入,一起打造非洲的支付宝;现需要招聘以下人员:

职位:前端开发工程师(中高级)、前端开发经理

职责描述:
1、在uni-app框架下,进行移动多端(iOS、Android、微信小程序)开发;
2、根据产品经理的需求和UI设计进行页面开发、功能开发;
3、负责公司APP的开发、迭代与优化;
4、参与APP研发技术的积累、学习、实践工作;
5、负责公司APP团队人员培养,队伍建设、技术路线发展等(管理岗)

任职要求:
1、3年以上前端开发工作经验,至少两个uniapp项目开发经验;
2、精通前端基本技术,包括HTML、CSS、Javacript 等;
3、精通JSON、XML等通信格式以及基于AJAX请求实现与后台数据交互;
4、熟悉微信生态及微信小程序生态,有完整的微信小程序项目经验;
5、熟悉使用HBuilder IDE编辑器进行开发,并完成打包发布安卓、ios版本app;
6、精通Vue、uni-app框架应用,并能运用uni-app框架完成移动端及小程序开发;
7、大专及以上学历,责任心强,有团队精神,学习能力强

工作地点:天津 河东区远洋国际中心A座29层
简历请投递:zhaopin@murongtech.com

收起阅读 »

App“必要性”合规,需要这样依照《规定》!

法律科普

国家互联网信息办公室、工业和信息化部、公安部和国家市场监督管理总局(“四部委”)联合发布的《常见类型移动互联网应用程序必要个人信息范围规定》(以下简称“《规定》”)5月1日正式实施。

自2021年3月初《规定》颁布以来,多数企业立即针对《规定》展开自查,力争将业务所涉及的App类型收集的信息限制在“必要信息范围”之内,自查过程中企业会面对怎样的难点?需要重视哪些条款? 此文基于实务,讨论企业依照《规定》完成个人信息保护合规的具体路径。

小程序也要严格遵守《规定》

根据《规定》第二条规定,若企业运营App或小程序,且该App或小程序存在收集用户个人信息行为,则应当遵守《规定》的要求

在实践中,小程序被纳入监管范围之内已经不存在争议,需要注意的是对小程序现有规定标准的准确把握。以微信小程序为例,不少小程序因其形式上作为小程序,相应的隐私保护设计“自行改装”。例如,大多数小程序没有实现传统App常见的交互,常常仅以一条主动勾选的动态链接代替需要获取用户明确同意的弹窗界。

随着《规定》的出台,小程序应对齐传统App的监管标准。从合规角度而言,小程序应立即调整为与传统App完全一致的交互设计方案。例如,需要获取用户明确同意时,小程序不应再继续简化模式,而应配置具体的符合一般要求的弹窗;又如,如果涉及调用可以收集用户个人信息敏感权限的,小程序也应当设置相应的说明窗口,在启用具体功能时获取用户的授权同意。总之,小程序并不能因为其形式上的特殊性而减免其个人信息保护的责任

此外还应注意,小程序作为“应用软件开放平台”的接入方,本身还应遵从平台方的相应规定,向平台方报备涉及个人信息处理的举措及信息。仍以微信小程序为例,某一小程序通过平台报备而向公众公示的数据包括:开发者信息、服务和数据的来源信息(网址)、服务商信息、用户隐私及数据提示等

由于小程序的实际控制者、开发者、运营者可能并非同一主体,填报工作可能由运营者为快速上线而随意完成,导致小程序的公示信息与其实际运营信息存在差距和混淆,最终小程序的个人信息收集方(控制者)未能履行向个人信息主体告知的义务。鉴此,在实践过程中,小程序的实际控制者应在委托其他方开发运营小程序时,在明确约定个人数据处理的数据安全责任之余,还应特别注意协同对平台的申报责任,避免侵犯个人信息主体知情权

理解并明确必要个人信息的范围

《规定》出台对必要个人信息的范围进行了明确。《规定》第三条规定,“本规定所称必要个人信息,是指保障App基本功能服务正常运行所必需的个人信息,缺少该信息App即无法实现基本功能服务。具体是指消费侧用户个人信息,不包括服务供给侧用户个人信息。”据此,必要个人信息应当同时具备以下条件:

(1)是App基本业务功能所必需的个人信息;

(2)是消费侧用户个人信息。

这两个条件在企业实践中是高度关注的研判重点,也是《规定》对常见应用程序基本业务功能和必要个人信息进行划分的初衷。在以往的案例中,如何判断某信息是否是“App基本业务功能所必需的个人信息”,经常是企业关注重点之一。

首先,判断必要个人信息的前提是正确认定App的“基本业务功能”。按照《个人信息安全规范》(GB/T 35273-2020)附录C.2的指导,基本业务功能“应根据个人信息主体选择、使用所提供产品或服务的根本期待和最主要的需求”划定,但实践中并非每个App都具备清晰的设计逻辑。

对于某些探索期的应用程序而言,其设计思路在于尽可能多的命中用户的潜在需求,用户可能基于功能A选择了该产品,也可能基于功能B而选择该产品,其基本功能显然会以用户的主观感受为转移,从而导致必要个人信息的范畴也存在游离。在这种情况下,基本业务功能的确认是否正确,或是否能够存在多个基本功能,成为企业个人信息保护合规判断的重要一环。

确定基本业务功能后,如何判断其“所必需的个人信息”又成为了合规工作的重点。企业需要注意,合规判断并非某单一职能部门有能力作出,比如,法务部门认为在“定位和导航软件”功能下,无需收集用户的设备信息,但是,如果产品设计方从技术角度认为必须收集设备信息确保运营环境安全,则法务和技术部门需要共同根据《规定》做出统一判断。

切实落实对个人信息主体的告知义务

如上所述,必要个人信息作为用户所选择的基本业务功能所必需的个人信息,可以视为符合《个人信息安全规范》规定的“履约必要”条件,从而豁免个人信息控制者获取个人信息主体授权同意的义务,符合《规定》要求的必要个人信息无需征得个人信息主体的授权同意。但是个人信息控制者仍应落实对个人信息主体的告知义务。因此,《隐私政策》中仍应对基于“履约必要”条件收集的个人信息向个人信息主体进行告知

同时,如果基于“履约必要”条件收集的个人信息将用于数据分析并最终用于实现自动化决策、个性化推荐场景时,其目的显然已经超越了履约目的,因此应获取个人信息主体的额外授权同意。出于产品合规的目的,这个授权同意应当在告知个人信息主体必要个人信息范围时一并告知并获得授权同意。

同时,针对因授权同意而获取的个人信息,即便“履约必要”作为合法处理理由之一,仍应赋予其撤销权,且为保障该撤销权不影响基本功能的实现,基于“履约必要”目的和基于数据分析目的而收集的数据应分开表单存储。诸如此类,隐私设计细节,均应在产品设计之初考虑,并落实在《隐私政策》中告知用户。

对标《规定》,“升级”对个人信息和个人敏感信息的表述

《规定》第五条对于39类常见类型App的基本功能和必要个人信息范围以列举形式进行了明示,供企业在设计、投产、复核其自身App的合规情况作为有效对照。

需要注意的是,《规定》对不同类别App个人信息获取范围做了明确,相对以往的规范有了增减,新增表述字段梳理如下

APP类型 新增必要个人信息字段

  • 网上购物类 支付渠道

  • 餐饮外卖类 支付渠道

  • 交通票务类 车次/船次/航班号、席别/舱位等级、座位号(如有)

  • 房屋租售类 面积/户型、期望售价或租金

  • 问诊挂号类 预约挂号的医院和科室

  • 旅游服务类 旅游目的地、旅游时间

  • 酒店服务类 入住和退房时间、入住酒店名称

  • 演出票务类 观演场次、座位号(如有);支付渠道

这些被明确认定为个人信息的表述,几乎都是个人信息中能够反映个人信息主体行踪轨迹、健康状况和财产状况的个人信息,如果按照“一旦泄露、非法提供或滥用可能危害人身和财产安全,极易导致个人名誉、身心健康受到损害或歧视性待遇等”的标准判断,此类信息均足以视为个人敏感信息。

鉴此,企业在个人信息保护合规工作中,需要业务进一步“升级”:

(1)在合规表述中,扩充个人信息和个人敏感信息的字段示例范围;

(2)扩充数据分级分类标准,将能够反映个人信息主体行踪轨迹、健康状况和财产状况的个人信息提高敏感级别。

【作者: 周杨 史蕾 来源:本文由中国网络空间安全协会个人信息保护专家工作组供稿】,声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。 邮箱地址:pufa@dcloud.io 。

原文链接

继续阅读 »

国家互联网信息办公室、工业和信息化部、公安部和国家市场监督管理总局(“四部委”)联合发布的《常见类型移动互联网应用程序必要个人信息范围规定》(以下简称“《规定》”)5月1日正式实施。

自2021年3月初《规定》颁布以来,多数企业立即针对《规定》展开自查,力争将业务所涉及的App类型收集的信息限制在“必要信息范围”之内,自查过程中企业会面对怎样的难点?需要重视哪些条款? 此文基于实务,讨论企业依照《规定》完成个人信息保护合规的具体路径。

小程序也要严格遵守《规定》

根据《规定》第二条规定,若企业运营App或小程序,且该App或小程序存在收集用户个人信息行为,则应当遵守《规定》的要求

在实践中,小程序被纳入监管范围之内已经不存在争议,需要注意的是对小程序现有规定标准的准确把握。以微信小程序为例,不少小程序因其形式上作为小程序,相应的隐私保护设计“自行改装”。例如,大多数小程序没有实现传统App常见的交互,常常仅以一条主动勾选的动态链接代替需要获取用户明确同意的弹窗界。

随着《规定》的出台,小程序应对齐传统App的监管标准。从合规角度而言,小程序应立即调整为与传统App完全一致的交互设计方案。例如,需要获取用户明确同意时,小程序不应再继续简化模式,而应配置具体的符合一般要求的弹窗;又如,如果涉及调用可以收集用户个人信息敏感权限的,小程序也应当设置相应的说明窗口,在启用具体功能时获取用户的授权同意。总之,小程序并不能因为其形式上的特殊性而减免其个人信息保护的责任

此外还应注意,小程序作为“应用软件开放平台”的接入方,本身还应遵从平台方的相应规定,向平台方报备涉及个人信息处理的举措及信息。仍以微信小程序为例,某一小程序通过平台报备而向公众公示的数据包括:开发者信息、服务和数据的来源信息(网址)、服务商信息、用户隐私及数据提示等

由于小程序的实际控制者、开发者、运营者可能并非同一主体,填报工作可能由运营者为快速上线而随意完成,导致小程序的公示信息与其实际运营信息存在差距和混淆,最终小程序的个人信息收集方(控制者)未能履行向个人信息主体告知的义务。鉴此,在实践过程中,小程序的实际控制者应在委托其他方开发运营小程序时,在明确约定个人数据处理的数据安全责任之余,还应特别注意协同对平台的申报责任,避免侵犯个人信息主体知情权

理解并明确必要个人信息的范围

《规定》出台对必要个人信息的范围进行了明确。《规定》第三条规定,“本规定所称必要个人信息,是指保障App基本功能服务正常运行所必需的个人信息,缺少该信息App即无法实现基本功能服务。具体是指消费侧用户个人信息,不包括服务供给侧用户个人信息。”据此,必要个人信息应当同时具备以下条件:

(1)是App基本业务功能所必需的个人信息;

(2)是消费侧用户个人信息。

这两个条件在企业实践中是高度关注的研判重点,也是《规定》对常见应用程序基本业务功能和必要个人信息进行划分的初衷。在以往的案例中,如何判断某信息是否是“App基本业务功能所必需的个人信息”,经常是企业关注重点之一。

首先,判断必要个人信息的前提是正确认定App的“基本业务功能”。按照《个人信息安全规范》(GB/T 35273-2020)附录C.2的指导,基本业务功能“应根据个人信息主体选择、使用所提供产品或服务的根本期待和最主要的需求”划定,但实践中并非每个App都具备清晰的设计逻辑。

对于某些探索期的应用程序而言,其设计思路在于尽可能多的命中用户的潜在需求,用户可能基于功能A选择了该产品,也可能基于功能B而选择该产品,其基本功能显然会以用户的主观感受为转移,从而导致必要个人信息的范畴也存在游离。在这种情况下,基本业务功能的确认是否正确,或是否能够存在多个基本功能,成为企业个人信息保护合规判断的重要一环。

确定基本业务功能后,如何判断其“所必需的个人信息”又成为了合规工作的重点。企业需要注意,合规判断并非某单一职能部门有能力作出,比如,法务部门认为在“定位和导航软件”功能下,无需收集用户的设备信息,但是,如果产品设计方从技术角度认为必须收集设备信息确保运营环境安全,则法务和技术部门需要共同根据《规定》做出统一判断。

切实落实对个人信息主体的告知义务

如上所述,必要个人信息作为用户所选择的基本业务功能所必需的个人信息,可以视为符合《个人信息安全规范》规定的“履约必要”条件,从而豁免个人信息控制者获取个人信息主体授权同意的义务,符合《规定》要求的必要个人信息无需征得个人信息主体的授权同意。但是个人信息控制者仍应落实对个人信息主体的告知义务。因此,《隐私政策》中仍应对基于“履约必要”条件收集的个人信息向个人信息主体进行告知

同时,如果基于“履约必要”条件收集的个人信息将用于数据分析并最终用于实现自动化决策、个性化推荐场景时,其目的显然已经超越了履约目的,因此应获取个人信息主体的额外授权同意。出于产品合规的目的,这个授权同意应当在告知个人信息主体必要个人信息范围时一并告知并获得授权同意。

同时,针对因授权同意而获取的个人信息,即便“履约必要”作为合法处理理由之一,仍应赋予其撤销权,且为保障该撤销权不影响基本功能的实现,基于“履约必要”目的和基于数据分析目的而收集的数据应分开表单存储。诸如此类,隐私设计细节,均应在产品设计之初考虑,并落实在《隐私政策》中告知用户。

对标《规定》,“升级”对个人信息和个人敏感信息的表述

《规定》第五条对于39类常见类型App的基本功能和必要个人信息范围以列举形式进行了明示,供企业在设计、投产、复核其自身App的合规情况作为有效对照。

需要注意的是,《规定》对不同类别App个人信息获取范围做了明确,相对以往的规范有了增减,新增表述字段梳理如下

APP类型 新增必要个人信息字段

  • 网上购物类 支付渠道

  • 餐饮外卖类 支付渠道

  • 交通票务类 车次/船次/航班号、席别/舱位等级、座位号(如有)

  • 房屋租售类 面积/户型、期望售价或租金

  • 问诊挂号类 预约挂号的医院和科室

  • 旅游服务类 旅游目的地、旅游时间

  • 酒店服务类 入住和退房时间、入住酒店名称

  • 演出票务类 观演场次、座位号(如有);支付渠道

这些被明确认定为个人信息的表述,几乎都是个人信息中能够反映个人信息主体行踪轨迹、健康状况和财产状况的个人信息,如果按照“一旦泄露、非法提供或滥用可能危害人身和财产安全,极易导致个人名誉、身心健康受到损害或歧视性待遇等”的标准判断,此类信息均足以视为个人敏感信息。

鉴此,企业在个人信息保护合规工作中,需要业务进一步“升级”:

(1)在合规表述中,扩充个人信息和个人敏感信息的字段示例范围;

(2)扩充数据分级分类标准,将能够反映个人信息主体行踪轨迹、健康状况和财产状况的个人信息提高敏感级别。

【作者: 周杨 史蕾 来源:本文由中国网络空间安全协会个人信息保护专家工作组供稿】,声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。 邮箱地址:pufa@dcloud.io 。

原文链接

收起阅读 »

安卓微信支付-100 问题解决经历

之前没有用过安卓微信支付,这次接入以为和小程序之类的差不多,结果就疯狂报-100
查了很多资料,官网给的说法基本是检查参数
最后发现用安卓公共证书是不能调起的
自己生成了一个开发证书 并修改开放平台的签名,有十分钟的生效时间
然后杀死所有APP 包括微信。
重新调用就可以了
附上生成开发证书的地址。自己生成jdk版本过高也不行。到处是坑。
http://www.applicationloader.net/appuploader/keystore.php

继续阅读 »

之前没有用过安卓微信支付,这次接入以为和小程序之类的差不多,结果就疯狂报-100
查了很多资料,官网给的说法基本是检查参数
最后发现用安卓公共证书是不能调起的
自己生成了一个开发证书 并修改开放平台的签名,有十分钟的生效时间
然后杀死所有APP 包括微信。
重新调用就可以了
附上生成开发证书的地址。自己生成jdk版本过高也不行。到处是坑。
http://www.applicationloader.net/appuploader/keystore.php

收起阅读 »

h5+app 上传图片,使用io文件管理时,在真机运行环境可以正常读取文件但是在打包apk后就无法读取到文件了

"targetSdkVersion" : 28
这个不要选到最新29 换成28就可以了

"targetSdkVersion" : 28
这个不要选到最新29 换成28就可以了

利用webview的跳转的方式开发应用

HTML5+ Webview

通过webview界面跳转的方式开发本地界面,为什么偶尔会产生应用死掉,点解任何按钮都没有反应的情况,只能重新杀掉应用重新打开,才能恢复功能。
请大神们解惑!

webview = plus.webview.create('/pages/add_device.html', 'add_device', {  
        titleNView: {  
            backgroundColor: '#0055ff',  
            titleText: '搜索设备',  
            titleColor: '#ffffff',  
            autoBackButton: true  
        }  
    }, {  
        group_id: w.group_id,  
        group_name: w.group_name,  
    });  
    webview&&webview.show(as, null, function(){  
        webview=null;//避免快速点击打开多个页面  
    });  
继续阅读 »

通过webview界面跳转的方式开发本地界面,为什么偶尔会产生应用死掉,点解任何按钮都没有反应的情况,只能重新杀掉应用重新打开,才能恢复功能。
请大神们解惑!

webview = plus.webview.create('/pages/add_device.html', 'add_device', {  
        titleNView: {  
            backgroundColor: '#0055ff',  
            titleText: '搜索设备',  
            titleColor: '#ffffff',  
            autoBackButton: true  
        }  
    }, {  
        group_id: w.group_id,  
        group_name: w.group_name,  
    });  
    webview&&webview.show(as, null, function(){  
        webview=null;//避免快速点击打开多个页面  
    });  
收起阅读 »

另一种思路,100%好用的项目迁移方案,从wepy转uniapp

wepy uniapp

如果关注过项目迁移,都见过有那种工具转换的,比如官方也给出了参考工具:

https://uniapp.dcloud.io/translate

但实际项目中,这些根本是行不通的,比如wepy,uniapp 实现原理不同,转换出来的脚本就很难通用。

下面给出另一个思路,只针对微信小程序,不论是哪种工程,最终编译出来的结果,一定是微信能解析的。那如果我把两个不同工程编译输出的结果合并,并且解决依赖及冲突,就意味着是可行的。

我这里实际操作的是把原有的wepy工程,整合到uniapp中,理论上如果是其他项目,也可以采用类似的思路。

下面就是顺着这个思路,依次解决:

第一步, 整合两个工程

1、通过 cli 命令行新建uniapp工程,方法参照官方文档:

https://uniapp.dcloud.io/quickstart-cli

打开 package.json,添加 wepy 核心依赖:

    "wepy": "^1.7.2",  
    "wepy-async-function": "^1.4.7",  
    "wepy-plugin-filemin": "^1.3.14"

2、uniapp 工程根目录下创建 wepy 目录,把wepy工程代码放在这下面,像这样:

第二步,让wepy的编译输出和uniapp一致

把wepy.config.js 移到 uniapp 根目录,修改wepy.config.js,根据编译环境,设置不同的输出,如下:

if (process.env.NODE_ENV === 'production') {  
    module.exports.target = 'dist/build/mp-weixin/'  
} else {  
   module.exports.target = 'dist/dev/mp-weixin/'  
}

这样当编译 wepy 时,就会和uniapp 输出一致了。

第三步,整合页面信息 pages/xxxx 路径

uniapp 有一个 src/manifest.json ,在 mp-weixin 节点,添加 pages,把原有 app.wpy 里的pages 复制过来,如果有分包,也一样,注意字符串添加双引号,符合json规范,如下:

    "pages": [  
      "pages/guide",  
      "pages/index",  
      "pages/login",  
      "pages/trends/index",  
      ...  
    "subPackages": [  
      {  
        "root": "packageA",  
        "pages": [  
          "pages/read/interact",  
          "pages/read/badge"  
        ]  
      },

第四步、完善uniapp的 src/App.vue

这一步最核心,前后次序,逻辑不能有错。需要按照 wepy 逻辑,注入相关核心。

1、整合 globalData,uniapp 和 wepy 都有自己的全局,把wepy 的globalData 完整复制给 uniapp,如下:

2、高光的魔术时刻。在 Uniapp 的 App.vue => onLaunch 中通过如下代码注入 wepy的核心:

注意,原有 wepy 中 import 的包,在 uniapp 里一定要用 non_webpack_require,这只是单纯的路径引用。
如果Uniapp里直接 import,会被webpack 编入代码。如果不太理解,按我说的操作即可。

      this.globalData.sentry = sentry  

      // 构建 wepy 核心  
      let wepy = __non_webpack_require__('./../npm/wepy/lib/wepy.js')  
      __non_webpack_require__('./../npm/wepy-async-function/index.js')  

      let $wepyApp = wepy.default.$createApp(wepy.default.app, {  
        "noPromiseAPI": ["createSelectorQuery"],  
        "baseUrl": process.env.SERVER_URL + 'api/',   // 一些项目中用到的参数,根据自己需要设置  
        "oriUrl": process.env.SERVER_URL,  
        "indexTitle": "你的应用名",  
        "isDev": process.env.NODE_ENV !== 'production'  
      })  

      // 注入 globalData  
      wepy.default.$instance.globalData = this.globalData  
      wepy.default.$instance.use('promisify')  

      const wepyPage = __non_webpack_require__('./../npm/wepy/lib/page.js')  
      App($wepyApp);  

      this.globalData.systemInfo = uni.getSystemInfoSync();

注意promisy 这个,如果用了,必须引用下 non_webpack_require('./../npm/wepy-async-function/index.js')。

全局css就按需要写就好,css一般不会有什么冲突,可以完全copy。注意下语法是 scss 还是 less 就好,然后通过 <style lang="scss"> 指定

其他 wepy app.wpy中的业务代码部分,自己根据需要些,总之要完全替换好 App.vue。两个工程整合成否与否的关键,就是 App.vue,因为这个必须使用 Uniapp的。

最后一步,如何编译

1、打开 package.json,

修改 mp-weixin,注意必须加参数 --clean=0 (表示编译时,不清空输出目录)
添加 wepy 编译,加参数 -s wepy 是表示指定编译的源码路径 wepy,最后如下:

    "dev:wepy": "cross-env NODE_ENV=development wepy build -s wepy --no-cache --watch",  
    "dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --clean=0 --watch",  
    "build:wepy": "rimraf ./dist/build/mp-weixin/* && cross-env NODE_ENV=production wepy build -s wepy --no-cache",  
    "build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build --clean=0"

2、编译次序与发布

当开发环境时

先 npm run dev:wepy
再打开一个窗口: npm run dev:mp-weixin

无论修改哪个工程,都会热更新。但通常wepy不需要修改源码时,wepy 不用一直开着。

当产线发布时

npm run build:wepy,再运行 npm run build:mp-weixin

继续阅读 »

如果关注过项目迁移,都见过有那种工具转换的,比如官方也给出了参考工具:

https://uniapp.dcloud.io/translate

但实际项目中,这些根本是行不通的,比如wepy,uniapp 实现原理不同,转换出来的脚本就很难通用。

下面给出另一个思路,只针对微信小程序,不论是哪种工程,最终编译出来的结果,一定是微信能解析的。那如果我把两个不同工程编译输出的结果合并,并且解决依赖及冲突,就意味着是可行的。

我这里实际操作的是把原有的wepy工程,整合到uniapp中,理论上如果是其他项目,也可以采用类似的思路。

下面就是顺着这个思路,依次解决:

第一步, 整合两个工程

1、通过 cli 命令行新建uniapp工程,方法参照官方文档:

https://uniapp.dcloud.io/quickstart-cli

打开 package.json,添加 wepy 核心依赖:

    "wepy": "^1.7.2",  
    "wepy-async-function": "^1.4.7",  
    "wepy-plugin-filemin": "^1.3.14"

2、uniapp 工程根目录下创建 wepy 目录,把wepy工程代码放在这下面,像这样:

第二步,让wepy的编译输出和uniapp一致

把wepy.config.js 移到 uniapp 根目录,修改wepy.config.js,根据编译环境,设置不同的输出,如下:

if (process.env.NODE_ENV === 'production') {  
    module.exports.target = 'dist/build/mp-weixin/'  
} else {  
   module.exports.target = 'dist/dev/mp-weixin/'  
}

这样当编译 wepy 时,就会和uniapp 输出一致了。

第三步,整合页面信息 pages/xxxx 路径

uniapp 有一个 src/manifest.json ,在 mp-weixin 节点,添加 pages,把原有 app.wpy 里的pages 复制过来,如果有分包,也一样,注意字符串添加双引号,符合json规范,如下:

    "pages": [  
      "pages/guide",  
      "pages/index",  
      "pages/login",  
      "pages/trends/index",  
      ...  
    "subPackages": [  
      {  
        "root": "packageA",  
        "pages": [  
          "pages/read/interact",  
          "pages/read/badge"  
        ]  
      },

第四步、完善uniapp的 src/App.vue

这一步最核心,前后次序,逻辑不能有错。需要按照 wepy 逻辑,注入相关核心。

1、整合 globalData,uniapp 和 wepy 都有自己的全局,把wepy 的globalData 完整复制给 uniapp,如下:

2、高光的魔术时刻。在 Uniapp 的 App.vue => onLaunch 中通过如下代码注入 wepy的核心:

注意,原有 wepy 中 import 的包,在 uniapp 里一定要用 non_webpack_require,这只是单纯的路径引用。
如果Uniapp里直接 import,会被webpack 编入代码。如果不太理解,按我说的操作即可。

      this.globalData.sentry = sentry  

      // 构建 wepy 核心  
      let wepy = __non_webpack_require__('./../npm/wepy/lib/wepy.js')  
      __non_webpack_require__('./../npm/wepy-async-function/index.js')  

      let $wepyApp = wepy.default.$createApp(wepy.default.app, {  
        "noPromiseAPI": ["createSelectorQuery"],  
        "baseUrl": process.env.SERVER_URL + 'api/',   // 一些项目中用到的参数,根据自己需要设置  
        "oriUrl": process.env.SERVER_URL,  
        "indexTitle": "你的应用名",  
        "isDev": process.env.NODE_ENV !== 'production'  
      })  

      // 注入 globalData  
      wepy.default.$instance.globalData = this.globalData  
      wepy.default.$instance.use('promisify')  

      const wepyPage = __non_webpack_require__('./../npm/wepy/lib/page.js')  
      App($wepyApp);  

      this.globalData.systemInfo = uni.getSystemInfoSync();

注意promisy 这个,如果用了,必须引用下 non_webpack_require('./../npm/wepy-async-function/index.js')。

全局css就按需要写就好,css一般不会有什么冲突,可以完全copy。注意下语法是 scss 还是 less 就好,然后通过 <style lang="scss"> 指定

其他 wepy app.wpy中的业务代码部分,自己根据需要些,总之要完全替换好 App.vue。两个工程整合成否与否的关键,就是 App.vue,因为这个必须使用 Uniapp的。

最后一步,如何编译

1、打开 package.json,

修改 mp-weixin,注意必须加参数 --clean=0 (表示编译时,不清空输出目录)
添加 wepy 编译,加参数 -s wepy 是表示指定编译的源码路径 wepy,最后如下:

    "dev:wepy": "cross-env NODE_ENV=development wepy build -s wepy --no-cache --watch",  
    "dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --clean=0 --watch",  
    "build:wepy": "rimraf ./dist/build/mp-weixin/* && cross-env NODE_ENV=production wepy build -s wepy --no-cache",  
    "build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build --clean=0"

2、编译次序与发布

当开发环境时

先 npm run dev:wepy
再打开一个窗口: npm run dev:mp-weixin

无论修改哪个工程,都会热更新。但通常wepy不需要修改源码时,wepy 不用一直开着。

当产线发布时

npm run build:wepy,再运行 npm run build:mp-weixin

收起阅读 »

test

iOS12

test44444444444444444444444

test44444444444444444444444

小说网站源码+全自动采集规则+H5手机版页面

源码分享

  小说网站源码是一个基于web的系统,使用PHP、BootStrap、CSS、JavaScript和MySQL为数据库开发。它包含两个方面,即管理员端和用户端。这个PHP/MySQLi环境下的在小说站旨在帮助管理员一个简单的方法来更新和维护所有的在线图书,以供阅读者查阅。
  
  源码:xsymz.icu
  
  PHP中的在线小说站源码是一个使用PHP、JavaScript和CSS开发的简单项目。该项目包含管理员和用户端。管理员端管理所有的管理,如添加书籍、删除书籍和编辑书籍的详细信息,管理员在这个小说站系统的管理中扮演着重要的角色。
  
  对于用户部分,如果用户已经有账号,可以以用户身份登录,否则,他/她必须填写注册表以注册为用户。用户可以浏览已发行书籍的详细信息及其归还状态。该项目为学生和小说站做好图书记录、借阅和归还工作提供了方便。
  
  我们中的许多人最有可能的一天是通过阅读一本书来度过的,无论它是一个幻想系列、小说、惊悚片、浪漫和更多的选择。获得所有这些资源的最佳地点是在线小说站。我们都知道管理一个小说是不容易的,无论是资源站还是搜索站,这时,一套稳定高效的小说网站源码就是至关重要的。在这个PHP/MySQLi环境下的小说管理系统,管理员有权在所有交易中从借书、还书和图书类别。他还拥有管理所有书籍、管理借贷者和管理所有用户的能力。同时,用户可以根据自己想要的图书类型,方便地通过网上借阅图书,甚至可以在登录系统后更新自己的个人资料。
  
  小说网站源码系统结构:
  
  管理端
  
  1、仪表板
  
  2、借来的书
  
  3、还书
  
  4、图书种类
  
  5、管理书籍
  
  6、管理借款人
  
  7、管理用户
  
  8、登录和注销
  
  阅读段
  
  1、加书
  
  2、图书过滤
  
  3、关于我们
  
  4、联系人管理
  
  5、简况
  
  6、借书
  
  7、借阅图书一览表
  
  8、登录和注销
  
  小说站源码的安装方法:
  
  1、下载zip文件;
  
  2、下载并安装XAMPP;
  
  3、运行XAMPP控制面板并启动MySQL和Apache;
  
  4、去C:\xampp\htdocs并提取下载的zip文件(图书馆系统)在文件夹内;
  
  5、打开浏览器并转到localhost/phpmyadmin/创建数据库;
  
  6、单击新建以创建数据库;
  
  7、命名数据库数据库库;
  
  8、单击“导入”以导入sql语言文件;
  
  9、单击“选择文件”,然后选择可以在图书馆系统文件夹;
  
  10、单击go;
  
  11、打开浏览器并转到localhost/LibrarySystem/admin/
  
  访问管理员帐户
  
  用户名:admin
  
  密码:admin
  
  12、打开浏览器并转到localhost/LibrarySystem/
  
  访问管理员帐户
  
  你可以注册。
  
  关于源码
  
  这个小说网站源码使用PHP、JavaScript和CSS,并自动集成了多套采集规则。在介绍本系统的特点时,它包括管理部分和用户部分。所有的编辑更新,管理书籍作者都来自管理部门,这套源码的设计很简单,所以用户在工作时不会遇到任何困难。

继续阅读 »

  小说网站源码是一个基于web的系统,使用PHP、BootStrap、CSS、JavaScript和MySQL为数据库开发。它包含两个方面,即管理员端和用户端。这个PHP/MySQLi环境下的在小说站旨在帮助管理员一个简单的方法来更新和维护所有的在线图书,以供阅读者查阅。
  
  源码:xsymz.icu
  
  PHP中的在线小说站源码是一个使用PHP、JavaScript和CSS开发的简单项目。该项目包含管理员和用户端。管理员端管理所有的管理,如添加书籍、删除书籍和编辑书籍的详细信息,管理员在这个小说站系统的管理中扮演着重要的角色。
  
  对于用户部分,如果用户已经有账号,可以以用户身份登录,否则,他/她必须填写注册表以注册为用户。用户可以浏览已发行书籍的详细信息及其归还状态。该项目为学生和小说站做好图书记录、借阅和归还工作提供了方便。
  
  我们中的许多人最有可能的一天是通过阅读一本书来度过的,无论它是一个幻想系列、小说、惊悚片、浪漫和更多的选择。获得所有这些资源的最佳地点是在线小说站。我们都知道管理一个小说是不容易的,无论是资源站还是搜索站,这时,一套稳定高效的小说网站源码就是至关重要的。在这个PHP/MySQLi环境下的小说管理系统,管理员有权在所有交易中从借书、还书和图书类别。他还拥有管理所有书籍、管理借贷者和管理所有用户的能力。同时,用户可以根据自己想要的图书类型,方便地通过网上借阅图书,甚至可以在登录系统后更新自己的个人资料。
  
  小说网站源码系统结构:
  
  管理端
  
  1、仪表板
  
  2、借来的书
  
  3、还书
  
  4、图书种类
  
  5、管理书籍
  
  6、管理借款人
  
  7、管理用户
  
  8、登录和注销
  
  阅读段
  
  1、加书
  
  2、图书过滤
  
  3、关于我们
  
  4、联系人管理
  
  5、简况
  
  6、借书
  
  7、借阅图书一览表
  
  8、登录和注销
  
  小说站源码的安装方法:
  
  1、下载zip文件;
  
  2、下载并安装XAMPP;
  
  3、运行XAMPP控制面板并启动MySQL和Apache;
  
  4、去C:\xampp\htdocs并提取下载的zip文件(图书馆系统)在文件夹内;
  
  5、打开浏览器并转到localhost/phpmyadmin/创建数据库;
  
  6、单击新建以创建数据库;
  
  7、命名数据库数据库库;
  
  8、单击“导入”以导入sql语言文件;
  
  9、单击“选择文件”,然后选择可以在图书馆系统文件夹;
  
  10、单击go;
  
  11、打开浏览器并转到localhost/LibrarySystem/admin/
  
  访问管理员帐户
  
  用户名:admin
  
  密码:admin
  
  12、打开浏览器并转到localhost/LibrarySystem/
  
  访问管理员帐户
  
  你可以注册。
  
  关于源码
  
  这个小说网站源码使用PHP、JavaScript和CSS,并自动集成了多套采集规则。在介绍本系统的特点时,它包括管理部分和用户部分。所有的编辑更新,管理书籍作者都来自管理部门,这套源码的设计很简单,所以用户在工作时不会遇到任何困难。

收起阅读 »

字节抖音小程序使用$refs报错解决办法

经验分享

我做抖音小程序遇到这个问题,开发工具里一切正常,一旦真机使用时运行到$refs就报错
解决办法如下(困扰了我三天):
参考官网的“.sync修饰符

父组件:
<form-item ref="formItem" :isfromok.sync="isfromok"&gt;&lt;/form-item&gt;

components: {  
    formItem  
},  
data() {  
    return {  
        isfromok: false     //是否填写表单  
    };  
},  

子组件(直接修改父组件的值):
let data = 123456;
_this.$emit('update:isfromok',datas);

在父组件内可直接判断isfromok的值是否符合预期,不用再使用$refs了
如果需要执行子组件的方法,可以使用watch监听来实现,希望能够帮助更多的人

继续阅读 »

我做抖音小程序遇到这个问题,开发工具里一切正常,一旦真机使用时运行到$refs就报错
解决办法如下(困扰了我三天):
参考官网的“.sync修饰符

父组件:
<form-item ref="formItem" :isfromok.sync="isfromok"&gt;&lt;/form-item&gt;

components: {  
    formItem  
},  
data() {  
    return {  
        isfromok: false     //是否填写表单  
    };  
},  

子组件(直接修改父组件的值):
let data = 123456;
_this.$emit('update:isfromok',datas);

在父组件内可直接判断isfromok的值是否符合预期,不用再使用$refs了
如果需要执行子组件的方法,可以使用watch监听来实现,希望能够帮助更多的人

收起阅读 »

分享下安卓下文件和目录的读取,写入,移动,删除

Native.JS 文件 安卓

分享下安卓下目录和文件读取
注意需要安装排序库natsort.min.js,和 vm.$u.date 时间函数,可以用自己的函数代替

// #ifdef APP-PLUS  
//只能用于安卓 导入java类  
let File = plus.android.importClass("java.io.File");  
let BufferedReader = plus.android.importClass("java.io.BufferedReader");  
let FileReader = plus.android.importClass("java.io.FileReader");  
let FileWriter = plus.android.importClass("java.io.FileWriter");  
// 安卓11及一下可以在任意地方创建文件夹  /sdcard/自己的文件夹/1.txt  
// 安卓11(百度安卓目录限制) /storage/emulated/0/Download/自己的文件夹/1.txt  

//新建文件 newFiles("/sdcard/修止符/配置.json")  
    let newFiles = (name) => {  
        let directory = new File(name);  
        if (!directory.exists()) {  
            return directory.mkdirs(); //不存在创建目录  
        }  
        return false;  
    };  
//读取txt文件 readFile ("/sdcard/修止符/配置.json")  
    let readFile = (fileName) => {  
        let readFr = new File(fileName);  
        try {  
            let reader = new BufferedReader(new FileReader(readFr));  
            let txt;  
            let retxt = '';  
            while (true) {  
                txt = reader.readLine(); //读取文件  
                if (txt == null) {  
                    break;  
                }  
                retxt = retxt + '\r\n' + txt;  
            }  
            return retxt;  
        } catch (e) {  
            console.log(e)  
            return '';  
        }  
    };  
//写文件 whiteFile("/sdcard/修止符/配置.json",{"主键":"值"})  
    let whiteFile = (fileName, res) => {  
        res = res ? JSON.stringify(res) : ''; //对象转换为json文本  
        try {  
            //不加根目录创建文件(即用相对地址)的话directory.exists()这个判断一值都是false  
            let n = fileName.lastIndexOf("/");  
            if (n != -1) {  
                let fileDirs = fileName.substring(0, n);  
                let directory = new File(fileDirs);  
                if (!directory.exists()) {  
                    directory.mkdirs(); //不存在创建目录  
                }  
            }  
            let file = new File(fileName);  
            if (!file.exists()) {  
                file.createNewFile(); //创建文件  
            }  
            let fos = new FileWriter(fileName, false);  
            fos.write(res);  
            fos.close();  
            return true;  
        } catch (e) {  
            console.log(e);  
            return false;  
        }  
        return false;  
    };  
//删除文件或文件夹 deleteFile  ("/sdcard/修止符/待删除/配置.json")  
    let deleteFile = (fileName) => {  
        console.log(fileName);  
        let file = new File(fileName.replace('//', '/'));  
        if (file.isFile() && file.exists()) {  
            return file.delete();  
        } else if (file.isDirectory()) {  
            let flag = true;  
            let files = file.listFiles();  
            let lenI = files.length  
            for (let i = 0; i < lenI; i++) {  
                //删除子目录和文件  
                flag = deleteFile(files[i].getAbsolutePath());  
                if (!flag) break;  
            }  
            if (!flag) return false;  
            //删除当前空目录  
            return file.delete();  
        }  
    };  
//移动文件 moveFile ("/sdcard/修止符/待删除/配置.json","/sdcard/修止符/配置.json")  
    let moveFile = (oldfile, newfile) => {  
        let n = newfile.lastIndexOf("/");  
        if (n != -1) {  
            let fileDirs = newfile.substring(0, n);  
            let directory = new File(fileDirs);  
            if (!directory.exists()) {  
                directory.mkdirs(); //不存在创建目录  
            }  
        }  
        let file = new File(oldfile);  
        let nfile = new File(newfile);  
        return file.renameTo(nfile);  
    };  
//读取目录  readFileList ("/sdcard/修止符/")   注意需要安装排序库natsort.min.js, vm.$u.date 时间函数  
    let readFileList = (fileName) => {  
        let directory;  
        let path = vm.vuex_xzfdir;  
        let empty = vm.$u.test.isEmpty(fileName)  
        if (empty) {  
            directory = new File(vm.vuex_xzfdir);  
        } else {  
            path = fileName;  
            directory = new File(path);  
        }  
        if (!directory.exists()) {  
            directory.mkdirs();  
        }  
        let files = directory.listFiles();  
        //对文件和文件夹进行分类  
        let lenI = files.length  
        let folderArr = [];  
        let fileArr = [];  
        for (let i = 0; i < lenI; ++i) {  
            if (files[i].isFile()) {  
                fileArr.push({  
                    id: i,  
                    show: false,  
                    icon: 'file-text',  
                    path: path,  
                    fileName: files[i].getName(),  
                    CreationTime: vm.$u.date(new Date(files[i].lastModified()), 'yyyy年mm月dd日 hh时MM分ss秒')  
                });  
            } else {  
                folderArr.push({  
                    id: i,  
                    show: false,  
                    icon: 'list-dot',  
                    path: path,  
                    fileName: files[i].getName(),  
                    CreationTime: vm.$u.date(new Date(files[i].lastModified()), 'yyyy年mm月dd日 hh时MM分ss秒')  
                });  
            }  
        }  
        //对文件进行排序 需要安装排序库natsort.min.js  
        let sorter = natsort({  
            desc: vm.vuex_desc  
        });  
        fileArr.sort((a, b) => {  
            return sorter(a.fileName, b.fileName);  
        });  
        folderArr.sort((a, b) => {  
            return sorter(a.fileName, b.fileName);  
        })  
        let resultArr = folderArr.concat(fileArr);  
        return resultArr;  
    }  
    // #endif  
继续阅读 »

分享下安卓下目录和文件读取
注意需要安装排序库natsort.min.js,和 vm.$u.date 时间函数,可以用自己的函数代替

// #ifdef APP-PLUS  
//只能用于安卓 导入java类  
let File = plus.android.importClass("java.io.File");  
let BufferedReader = plus.android.importClass("java.io.BufferedReader");  
let FileReader = plus.android.importClass("java.io.FileReader");  
let FileWriter = plus.android.importClass("java.io.FileWriter");  
// 安卓11及一下可以在任意地方创建文件夹  /sdcard/自己的文件夹/1.txt  
// 安卓11(百度安卓目录限制) /storage/emulated/0/Download/自己的文件夹/1.txt  

//新建文件 newFiles("/sdcard/修止符/配置.json")  
    let newFiles = (name) => {  
        let directory = new File(name);  
        if (!directory.exists()) {  
            return directory.mkdirs(); //不存在创建目录  
        }  
        return false;  
    };  
//读取txt文件 readFile ("/sdcard/修止符/配置.json")  
    let readFile = (fileName) => {  
        let readFr = new File(fileName);  
        try {  
            let reader = new BufferedReader(new FileReader(readFr));  
            let txt;  
            let retxt = '';  
            while (true) {  
                txt = reader.readLine(); //读取文件  
                if (txt == null) {  
                    break;  
                }  
                retxt = retxt + '\r\n' + txt;  
            }  
            return retxt;  
        } catch (e) {  
            console.log(e)  
            return '';  
        }  
    };  
//写文件 whiteFile("/sdcard/修止符/配置.json",{"主键":"值"})  
    let whiteFile = (fileName, res) => {  
        res = res ? JSON.stringify(res) : ''; //对象转换为json文本  
        try {  
            //不加根目录创建文件(即用相对地址)的话directory.exists()这个判断一值都是false  
            let n = fileName.lastIndexOf("/");  
            if (n != -1) {  
                let fileDirs = fileName.substring(0, n);  
                let directory = new File(fileDirs);  
                if (!directory.exists()) {  
                    directory.mkdirs(); //不存在创建目录  
                }  
            }  
            let file = new File(fileName);  
            if (!file.exists()) {  
                file.createNewFile(); //创建文件  
            }  
            let fos = new FileWriter(fileName, false);  
            fos.write(res);  
            fos.close();  
            return true;  
        } catch (e) {  
            console.log(e);  
            return false;  
        }  
        return false;  
    };  
//删除文件或文件夹 deleteFile  ("/sdcard/修止符/待删除/配置.json")  
    let deleteFile = (fileName) => {  
        console.log(fileName);  
        let file = new File(fileName.replace('//', '/'));  
        if (file.isFile() && file.exists()) {  
            return file.delete();  
        } else if (file.isDirectory()) {  
            let flag = true;  
            let files = file.listFiles();  
            let lenI = files.length  
            for (let i = 0; i < lenI; i++) {  
                //删除子目录和文件  
                flag = deleteFile(files[i].getAbsolutePath());  
                if (!flag) break;  
            }  
            if (!flag) return false;  
            //删除当前空目录  
            return file.delete();  
        }  
    };  
//移动文件 moveFile ("/sdcard/修止符/待删除/配置.json","/sdcard/修止符/配置.json")  
    let moveFile = (oldfile, newfile) => {  
        let n = newfile.lastIndexOf("/");  
        if (n != -1) {  
            let fileDirs = newfile.substring(0, n);  
            let directory = new File(fileDirs);  
            if (!directory.exists()) {  
                directory.mkdirs(); //不存在创建目录  
            }  
        }  
        let file = new File(oldfile);  
        let nfile = new File(newfile);  
        return file.renameTo(nfile);  
    };  
//读取目录  readFileList ("/sdcard/修止符/")   注意需要安装排序库natsort.min.js, vm.$u.date 时间函数  
    let readFileList = (fileName) => {  
        let directory;  
        let path = vm.vuex_xzfdir;  
        let empty = vm.$u.test.isEmpty(fileName)  
        if (empty) {  
            directory = new File(vm.vuex_xzfdir);  
        } else {  
            path = fileName;  
            directory = new File(path);  
        }  
        if (!directory.exists()) {  
            directory.mkdirs();  
        }  
        let files = directory.listFiles();  
        //对文件和文件夹进行分类  
        let lenI = files.length  
        let folderArr = [];  
        let fileArr = [];  
        for (let i = 0; i < lenI; ++i) {  
            if (files[i].isFile()) {  
                fileArr.push({  
                    id: i,  
                    show: false,  
                    icon: 'file-text',  
                    path: path,  
                    fileName: files[i].getName(),  
                    CreationTime: vm.$u.date(new Date(files[i].lastModified()), 'yyyy年mm月dd日 hh时MM分ss秒')  
                });  
            } else {  
                folderArr.push({  
                    id: i,  
                    show: false,  
                    icon: 'list-dot',  
                    path: path,  
                    fileName: files[i].getName(),  
                    CreationTime: vm.$u.date(new Date(files[i].lastModified()), 'yyyy年mm月dd日 hh时MM分ss秒')  
                });  
            }  
        }  
        //对文件进行排序 需要安装排序库natsort.min.js  
        let sorter = natsort({  
            desc: vm.vuex_desc  
        });  
        fileArr.sort((a, b) => {  
            return sorter(a.fileName, b.fileName);  
        });  
        folderArr.sort((a, b) => {  
            return sorter(a.fileName, b.fileName);  
        })  
        let resultArr = folderArr.concat(fileArr);  
        return resultArr;  
    }  
    // #endif  
收起阅读 »

新版lib.5plus.base-release.aar插件导致android离线打包隐私弹窗中对应链接点击后为空白页(包含解决办法)

离线打包 隐私政策 uniapp

现象:
使用3.1.2配置使用正常
使用3.1.13+版本,安装应用后的隐私弹窗,点击其中的链接跳到空白页面,复制网址提示复制null
通过与3.1.2版本互换插件,将问题定位到lib.5plus.base-release.aar上
奇怪的是这个问题在as自带的模拟器上不存在,在真机上才存在

原因:
因为我们应用使用的是uniapp范例中的文案,所以一直以为是我们在strings.xml中的配置项目与新版插件不兼容导致
实际上本质是,我们的配置项目根本就没生效,看到的是lib.5plus.base-release.aar中携带的默认值,变更文案后可以发现模拟器中变更了,但是真机还是原样

造成原因是:我们的string配置按照demo写在了res/values/下,
3.1.2的lib.5plus.base-release.aar自带字符串资源只有values(中文) 和values-en(英文),编译时资源合并顺序最后写入自定义配置,可以生效。
而新版的lib.5plus.base-release.aar自带字符串资源有values(默认,英文?) 和values-en(英文),以及values-zh(中文)。
因为values的定义发生了变化,而离线打包sdk中demo使用的还是values,因此我们配置的项目,只会覆盖value的默认项目,并不会覆盖values-zh
而实际上真机因为是中文系统会默认使用values-zh,导致使用的字符串dcloud_privacy_prompt_message还是lib.5plus.base-release.aar中的默认值,其中对应的href是"",自然到了浏览器就是空值

解决办法:
res下的values目录复制一份更名为values-zh

这个问题应该是官方想要增强多语言的支持能力修订了相关的定义导致。
因为过于诡异,而且更诡异的是社区完全看不到类似的问题,特此提交一个说明,希望能够帮到有需要的人。
也希望官方能够在后续处理此类问题时兼顾考虑demo和相关配置文档的修订。

继续阅读 »

现象:
使用3.1.2配置使用正常
使用3.1.13+版本,安装应用后的隐私弹窗,点击其中的链接跳到空白页面,复制网址提示复制null
通过与3.1.2版本互换插件,将问题定位到lib.5plus.base-release.aar上
奇怪的是这个问题在as自带的模拟器上不存在,在真机上才存在

原因:
因为我们应用使用的是uniapp范例中的文案,所以一直以为是我们在strings.xml中的配置项目与新版插件不兼容导致
实际上本质是,我们的配置项目根本就没生效,看到的是lib.5plus.base-release.aar中携带的默认值,变更文案后可以发现模拟器中变更了,但是真机还是原样

造成原因是:我们的string配置按照demo写在了res/values/下,
3.1.2的lib.5plus.base-release.aar自带字符串资源只有values(中文) 和values-en(英文),编译时资源合并顺序最后写入自定义配置,可以生效。
而新版的lib.5plus.base-release.aar自带字符串资源有values(默认,英文?) 和values-en(英文),以及values-zh(中文)。
因为values的定义发生了变化,而离线打包sdk中demo使用的还是values,因此我们配置的项目,只会覆盖value的默认项目,并不会覆盖values-zh
而实际上真机因为是中文系统会默认使用values-zh,导致使用的字符串dcloud_privacy_prompt_message还是lib.5plus.base-release.aar中的默认值,其中对应的href是"",自然到了浏览器就是空值

解决办法:
res下的values目录复制一份更名为values-zh

这个问题应该是官方想要增强多语言的支持能力修订了相关的定义导致。
因为过于诡异,而且更诡异的是社区完全看不到类似的问题,特此提交一个说明,希望能够帮到有需要的人。
也希望官方能够在后续处理此类问题时兼顾考虑demo和相关配置文档的修订。

收起阅读 »