HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

云函数,云数据库,云存储应该全部走云服务商的内网,不然相比传统毫无优势

uniCloud

现在都走外网所以慢。
这个不论规模大小,阿里云应该都能实现的。
默认走内网吧,实在找不到什么理由默认走外网哦。

现在都走外网所以慢。
这个不论规模大小,阿里云应该都能实现的。
默认走内网吧,实在找不到什么理由默认走外网哦。

想做一款小程序,小程序与APP相比有什么优缺点?

微信小程序

微信小程序的优势小程序的特点小程序的开发周期小程序适合什么样的用户怎样运营自己的小程序能给自己带来什么?

小程序有哪些优势?

对于用户来说,小程序与APP相比,用户不用下载,想使用的时候直接打开就可以了,不用的时候直接关掉,即用即走,不占没存,不需要安装卸载。
小程序主要的样式代码都封装在微信小程序里面,打开速度相对h5来说更加的快速,并且已经很接近原生APP。
微信小程序可以添加到手机桌面,看上去效果和APP是差不多的,用户在使用时可以直接在桌面上找到,以及直接消除,可以说非常的方便。当然这点仅限于安卓手机。
运行速度和APP差不多,可以实现APP90%的功能,要比h5强太多,开发成本和h5差不多,要比APP节省一部分开发成本。
能够调用通讯录、蓝牙等深度系统权限,应用体验比H5页面更流畅。
小程序有哪些缺点?

首当其先的就是小程序的推送能力,小程序目前只能通过分享将其分享至好友列表的好友,不能转发到朋友圈,这对于一些需要借助朋友圈人脉网络裂变式扩散的需求,就显得不太好了。
小程序不支持随意跳转外链,每个外链都需要到后台“开发设置”里添加业务域名,所以间接地影响到了小程序的开放性,这样就限制了其他支付方式以及功能的接入,这也决定了基于小程序,难以构建起信息整合、分发的一站式平台。
微信小程序只有2M大小,这就导致无法开发一些大型的小程序。所以目前你会看到很多小程序很小很简单。如果追求品质、细节的复杂应用,建议在APP上进行。
小程序需要像APP一样上架,相比于h5的即做即发要麻烦点,并且小程序每次提交版本都需要微信团队的审核,更新频繁的话确实是很麻烦。
所以,选择开发小程序或者APP要根据自己的需求进行,取其长而避其短,透过外表看本质你才能更进一步知道你做小程序或者是APP的目的,想怎样推广引流,想怎样运营,需要避开一些小程序无法实现的,或是不容易实现的,根据这些来判断自己是否要做小程序。

继续阅读 »

微信小程序的优势小程序的特点小程序的开发周期小程序适合什么样的用户怎样运营自己的小程序能给自己带来什么?

小程序有哪些优势?

对于用户来说,小程序与APP相比,用户不用下载,想使用的时候直接打开就可以了,不用的时候直接关掉,即用即走,不占没存,不需要安装卸载。
小程序主要的样式代码都封装在微信小程序里面,打开速度相对h5来说更加的快速,并且已经很接近原生APP。
微信小程序可以添加到手机桌面,看上去效果和APP是差不多的,用户在使用时可以直接在桌面上找到,以及直接消除,可以说非常的方便。当然这点仅限于安卓手机。
运行速度和APP差不多,可以实现APP90%的功能,要比h5强太多,开发成本和h5差不多,要比APP节省一部分开发成本。
能够调用通讯录、蓝牙等深度系统权限,应用体验比H5页面更流畅。
小程序有哪些缺点?

首当其先的就是小程序的推送能力,小程序目前只能通过分享将其分享至好友列表的好友,不能转发到朋友圈,这对于一些需要借助朋友圈人脉网络裂变式扩散的需求,就显得不太好了。
小程序不支持随意跳转外链,每个外链都需要到后台“开发设置”里添加业务域名,所以间接地影响到了小程序的开放性,这样就限制了其他支付方式以及功能的接入,这也决定了基于小程序,难以构建起信息整合、分发的一站式平台。
微信小程序只有2M大小,这就导致无法开发一些大型的小程序。所以目前你会看到很多小程序很小很简单。如果追求品质、细节的复杂应用,建议在APP上进行。
小程序需要像APP一样上架,相比于h5的即做即发要麻烦点,并且小程序每次提交版本都需要微信团队的审核,更新频繁的话确实是很麻烦。
所以,选择开发小程序或者APP要根据自己的需求进行,取其长而避其短,透过外表看本质你才能更进一步知道你做小程序或者是APP的目的,想怎样推广引流,想怎样运营,需要避开一些小程序无法实现的,或是不容易实现的,根据这些来判断自己是否要做小程序。

收起阅读 »

拼拼有礼商城模式定制开发

小程序

多人拼团一人中奖、三人拼团一人中奖、五人拼团一人中奖系统、十人拼团三人中奖模式、三十人拼购3人中奖、百人拼团N人中团的软件、小程序、公众号、H5手机网页版版本、APP版本的均可制作、开发流程?
现在拼团是短时间内通过价集中人气吸引购买的营销活动,通常以较少的商品数量和较低的价格作为噱头,限定开始购买的时间后,会在以秒为单位的时间内被抢购一空。这一营销功能在第三方商城平台上的应用也已非常普遍了。与拼团一样,拼团也能在活动期间聚集大量人气,为拼团拼团小程序商城引流。
丰富的营销活动,、团购、限时抢购,天天都有新玩法。
一键转发,图文分享,拉新拓客,快速起量,抓住更多流量,先人一步抢占市场。
舒适的用户体验,性能快速流畅,不卡顿,用户不流失。
快速实现企业规模扩张,脱颖而出,得到资本市场的青睐!
会员下单,团长收益立即可见,总部结算,自由。
订单到货自动通知,一键取货快捷操作。
团长销售排名,经营数据,清晰展现,随时掌握团长动态。
团长分级,差异化佣金管理,多劳多得,深度绑定,互利双赢!

继续阅读 »

多人拼团一人中奖、三人拼团一人中奖、五人拼团一人中奖系统、十人拼团三人中奖模式、三十人拼购3人中奖、百人拼团N人中团的软件、小程序、公众号、H5手机网页版版本、APP版本的均可制作、开发流程?
现在拼团是短时间内通过价集中人气吸引购买的营销活动,通常以较少的商品数量和较低的价格作为噱头,限定开始购买的时间后,会在以秒为单位的时间内被抢购一空。这一营销功能在第三方商城平台上的应用也已非常普遍了。与拼团一样,拼团也能在活动期间聚集大量人气,为拼团拼团小程序商城引流。
丰富的营销活动,、团购、限时抢购,天天都有新玩法。
一键转发,图文分享,拉新拓客,快速起量,抓住更多流量,先人一步抢占市场。
舒适的用户体验,性能快速流畅,不卡顿,用户不流失。
快速实现企业规模扩张,脱颖而出,得到资本市场的青睐!
会员下单,团长收益立即可见,总部结算,自由。
订单到货自动通知,一键取货快捷操作。
团长销售排名,经营数据,清晰展现,随时掌握团长动态。
团长分级,差异化佣金管理,多劳多得,深度绑定,互利双赢!

收起阅读 »

uniapp + 纯nuve开发的一个app, 推荐给大家




句馆是一款基于文艺生活为兴趣匹配交友的社区,本社区以经典句签、短视频、动态分享、匹配交友、兴趣圈子等为核心功能。简洁化的设计风格,是复杂社会难能可贵的心灵净土。句子虽短,总能入心,我们致力于打造纯净化交友社区,在句馆,遇见有趣的灵魂。

【句签】汇聚海量美句,收录数万作者,感悟生活,品读经典

【视频】情感、读书、影视等各大领域达人入驻,指尖精彩触手可及

【动态】用心生活,记录美好,你的每个精彩动态都会遇到一次心动

【联系句馆】
官方邮箱:kf@juguanapp.com
官方网站:www.juguanapp.com

各大应用市场均已上架 搜索 句馆
应用宝下载地址:https://a.app.qq.com/o/simple.jsp?pkgname=vip.juguan
下载地址

继续阅读 »




句馆是一款基于文艺生活为兴趣匹配交友的社区,本社区以经典句签、短视频、动态分享、匹配交友、兴趣圈子等为核心功能。简洁化的设计风格,是复杂社会难能可贵的心灵净土。句子虽短,总能入心,我们致力于打造纯净化交友社区,在句馆,遇见有趣的灵魂。

【句签】汇聚海量美句,收录数万作者,感悟生活,品读经典

【视频】情感、读书、影视等各大领域达人入驻,指尖精彩触手可及

【动态】用心生活,记录美好,你的每个精彩动态都会遇到一次心动

【联系句馆】
官方邮箱:kf@juguanapp.com
官方网站:www.juguanapp.com

各大应用市场均已上架 搜索 句馆
应用宝下载地址:https://a.app.qq.com/o/simple.jsp?pkgname=vip.juguan
下载地址

收起阅读 »

解决打不开内置浏览器的问题(提示:[WARNING:] error : "无法加载库XX\builtincef3browser.dll:找不到指定的程序。")

内置浏览器

上个月在官网中提了这个问题,虽然官方及时回复,但没解决问题。空下来网上搜了一些,又尝试了一番,有两个解决办法:
1、在网上找到的方法:只需要将 bin目录下的 libcef.dll、cef.pak、icudtl.dat、natives_blob.bin、snapshot_blob.bin 文件剪切(或复制、软链接)到 Hbuilder.exe 同目录下即可解决。
2、如果你和我一样是完美主义患者,不想动bin下的文件(因为升级时很有可能重新下载),那也简单,只需在运行 HBuilderX.exe 前将环境变量PATH中加入 bin 目录的绝对路径即可,具体操作如下:
a、新建一个批处理 run.bat,并编辑。
b、加入:
set PATH=HBuilderX的安装路径\bin;%PATH%;
start "" HBuilderX.exe的路径
比如我的:
set PATH=%~dp0HBuilderX\bin;%PATH%;
start "" HBuilderX\HBuilderX.exe
这样就可以解决了。
看来官方在运行HBuilderX.exe时并没有把bin添加进环境变量中,希望官方能解决一下这个问题(Qt中也就一句代码的事)。

继续阅读 »

上个月在官网中提了这个问题,虽然官方及时回复,但没解决问题。空下来网上搜了一些,又尝试了一番,有两个解决办法:
1、在网上找到的方法:只需要将 bin目录下的 libcef.dll、cef.pak、icudtl.dat、natives_blob.bin、snapshot_blob.bin 文件剪切(或复制、软链接)到 Hbuilder.exe 同目录下即可解决。
2、如果你和我一样是完美主义患者,不想动bin下的文件(因为升级时很有可能重新下载),那也简单,只需在运行 HBuilderX.exe 前将环境变量PATH中加入 bin 目录的绝对路径即可,具体操作如下:
a、新建一个批处理 run.bat,并编辑。
b、加入:
set PATH=HBuilderX的安装路径\bin;%PATH%;
start "" HBuilderX.exe的路径
比如我的:
set PATH=%~dp0HBuilderX\bin;%PATH%;
start "" HBuilderX\HBuilderX.exe
这样就可以解决了。
看来官方在运行HBuilderX.exe时并没有把bin添加进环境变量中,希望官方能解决一下这个问题(Qt中也就一句代码的事)。

收起阅读 »

最高检:网络黑灰产成为网络犯罪多发高发的重要原因

法律科普

最高人民检察院1月25日召开新闻发布会,最高检检察委员会委员、第四检察厅厅长郑新俭介绍了近年来检察机关办案中,当前网络犯罪呈现的五大趋势

一是犯罪案件数量上升迅猛。

近年来,检察机关办理网络犯罪案件以年均近40%的速度攀升,2020年达到了54%。特别是战“疫”期间检察机关办理的诈骗犯罪案件中,有三分之一是利用网络实施。在所有网络犯罪中,网络诈骗、网络赌博(包括开设赌场罪和赌博罪)高位运行,成为当前主要网络犯罪。

二是网络黑灰产形成生态圈,为犯罪持续“输血供粮”。

黑灰产上游为犯罪集团提供技术工具、收集个人信息,或为导流获客、广告推广;中游实施诈骗或开设赌场等犯罪;下游利用支付通道“洗白”资金,构建起完整黑灰产生态圈。规模庞大的地下黑产密切配合,为网络犯罪持续“输血供粮”,成为网络犯罪多发高发的重要原因。

三是犯罪手段花样更新。

网上网下、境内境外、虚拟现实相互结合,网络犯罪手段方式交织升级。据不完全统计,当前网络诈骗手法多达6大类300多种,而且还在不断“推陈出新”。

四是犯罪主体呈现向“三低”人群发展的态势。

网络犯罪非接触性降低犯罪悖德感和罪恶感、超长的黑灰产业链细化犯罪分工,降低犯罪专业门槛,加之超高的收益,致使大量法律意识薄弱、社会经验不足的人步入犯罪“陷阱”。网络犯罪主体开始向低龄、低学历、低收入“三低”人群发展,一些在校学生、社会务工人员都深陷其中。

五是犯罪危害叠加升级。

网络犯罪危害在政治、经济、社会、文化等层面相互交织传导,社会危害“量”的积累往往短时间内导致“质”的突变,敏感的生活“小”信息往往会酿成严重的社会“大”事件。

郑新俭同时还表示,此前针对网络诽谤等严重扰乱网络社会公共秩序的行为,检察机关建议公安机关对“杭州女子取快递被造谣案”立案侦查,推动刑事自诉案件转为公诉,向社会传递“网络空间不是法外之地”的强烈信号。

最高人民检察院同日还发布了《人民检察院办理网络犯罪案件规定》(以下简称《规定》)。《规定》以办案流程为脉络,以事实证据审查为主线,对检察机关办理网络犯罪案件提出了规范指引,对办案技术融合、一体协作办案等机制建设提出了具体要求,以更好提升办案质效,推动网络治理,维护网络安全。

【转自:凤凰网,来源:人民网】,声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。 邮箱地址:pufa@dcloud.io 。

原文链接

继续阅读 »

最高人民检察院1月25日召开新闻发布会,最高检检察委员会委员、第四检察厅厅长郑新俭介绍了近年来检察机关办案中,当前网络犯罪呈现的五大趋势

一是犯罪案件数量上升迅猛。

近年来,检察机关办理网络犯罪案件以年均近40%的速度攀升,2020年达到了54%。特别是战“疫”期间检察机关办理的诈骗犯罪案件中,有三分之一是利用网络实施。在所有网络犯罪中,网络诈骗、网络赌博(包括开设赌场罪和赌博罪)高位运行,成为当前主要网络犯罪。

二是网络黑灰产形成生态圈,为犯罪持续“输血供粮”。

黑灰产上游为犯罪集团提供技术工具、收集个人信息,或为导流获客、广告推广;中游实施诈骗或开设赌场等犯罪;下游利用支付通道“洗白”资金,构建起完整黑灰产生态圈。规模庞大的地下黑产密切配合,为网络犯罪持续“输血供粮”,成为网络犯罪多发高发的重要原因。

三是犯罪手段花样更新。

网上网下、境内境外、虚拟现实相互结合,网络犯罪手段方式交织升级。据不完全统计,当前网络诈骗手法多达6大类300多种,而且还在不断“推陈出新”。

四是犯罪主体呈现向“三低”人群发展的态势。

网络犯罪非接触性降低犯罪悖德感和罪恶感、超长的黑灰产业链细化犯罪分工,降低犯罪专业门槛,加之超高的收益,致使大量法律意识薄弱、社会经验不足的人步入犯罪“陷阱”。网络犯罪主体开始向低龄、低学历、低收入“三低”人群发展,一些在校学生、社会务工人员都深陷其中。

五是犯罪危害叠加升级。

网络犯罪危害在政治、经济、社会、文化等层面相互交织传导,社会危害“量”的积累往往短时间内导致“质”的突变,敏感的生活“小”信息往往会酿成严重的社会“大”事件。

郑新俭同时还表示,此前针对网络诽谤等严重扰乱网络社会公共秩序的行为,检察机关建议公安机关对“杭州女子取快递被造谣案”立案侦查,推动刑事自诉案件转为公诉,向社会传递“网络空间不是法外之地”的强烈信号。

最高人民检察院同日还发布了《人民检察院办理网络犯罪案件规定》(以下简称《规定》)。《规定》以办案流程为脉络,以事实证据审查为主线,对检察机关办理网络犯罪案件提出了规范指引,对办案技术融合、一体协作办案等机制建设提出了具体要求,以更好提升办案质效,推动网络治理,维护网络安全。

【转自:凤凰网,来源:人民网】,声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。 邮箱地址:pufa@dcloud.io 。

原文链接

收起阅读 »

图片预览手动关闭api

uniapp

uni.previewImage 预览图片需要用户主动关闭
可不可以增加关闭api

uni.previewImage 预览图片需要用户主动关闭
可不可以增加关闭api

『兼容H5+小程序+App/Nvue』uniapp自定义弹框uaPopup组件(升级版)

uniapp uniapp插件

基于uni-app开发兼容全端自定义弹出框ua-popup插件,可完美运行在h5、小程序及app端。

uaPopup 一款整合了msg信息框、alert提示框、dialog对话框、actionSheet底部面板框、toast轻提示框、android/ios弹窗等多种弹窗效果。可以自定义弹窗样式及按钮样式和事件、多个弹窗嵌套显示,支持自定义插槽模板内容。

如下图:h5/小程序/app端效果
img

可覆盖在Nvue原生页面video组件之上

img

引入组件

uapopup 支持全局main.js引入或页面单独引入使用。

import UAPopup from './components/ua-popup/index.vue'  
Vue.component('ua-popup', UAPopup)

自hbuilderx2.5起 支持easycom组件模式。根据使用习惯,也可以改为components/ua-popup/ua-popup.vue方式,系统会自定义识别组件,无需再手动注册引入。

使用组件

ua-popup支持组件写法和函数式写法来调用组件。

  • 组件式调用
<!-- msg提示 -->  
<ua-popup v-model="showMsg" anim="fadeIn" content="上善若水,水利万物而不争" shadeClose="false" time="3" />  

<!-- 询问框 -->  
<ua-popup v-model="showConfirm" shadeClose="false" title="标题" xclose z-index="2001"  
    content="<div style='color:#ff557f;padding:20px 40px;'>一切都将一去杳然,任何人都无法将其捕获。</div>"  
    :btns="[  
        {text: '取消', click: hideConfirm},  
        {text: '确定', style: 'color:#00aa00;', click: handleInfo},  
    ]"  
/>
  • 函数式调用
// 函数式多层嵌套  
handleInfo() {  
    let $ua = this.$refs.uapopup  
    let $toast = this.$refs.uatoast  
    $ua.open({  
        content: '人生漫漫,且行且珍惜',  
        customStyle: {'background-color': 'rgba(170, 0, 127, 0.6)', 'color': '#fff'},  
        time: 3,  
        onClose() {  
            $ua.open({  
                type: 'android',  
                content: '<div style="color:#aa007f">预测未来的最好办法是自己亲手创造未来</div>',  
                customStyle: {'width': '200px'},  
                zIndex: 202120,  
                btns: [  
                    {  
                        text: 'close', click() {  
                            $ua.close()  
                        }  
                    },  
                    {  
                        text: 'Get一下',  
                        style: 'color:#00aa00;',  
                        click() {  
                            $toast.open({  
                                type: 'toast',  
                                icon: 'loading',  
                                content: '请稍后...',  
                                opacity: .2,  
                                time: 2,  
                                zIndex: 202125,  
                            })  
                        }  
                    }  
                ]  
            })  
        }  
    })  
}

img

img

编码开发

  • 支持如下20+参数自定义配置。
props: {  
    value: { type: Boolean, default: false },  
    title: String,  
    content: String,  
    type: String,  
    customStyle: { type: Object, default: null },  
    icon: String,  
    shade: { type: [Boolean, String], default: true },  
    shadeClose: { type: [Boolean, String], default: true },  
    opacity: { type: [Number, String], default: '' },  
    round: Boolean,  
    xclose: Boolean,  
    xposition: { type: String, default: 'right' },  
    xcolor: { type: String, default: '#333' },  
    anim: { type: String, default: 'scaleIn' },  
    position: String,  
    follow: { type: Array, default: null },  
    time: { type: [Number, String], default: 0 },  
    zIndex: { type: [Number, String], default: '202107' },  
    btns: {  
        type: Array, default: null  
    },  
    // 打开弹框回调  
    onOpen: { type: Function, default: null },  
    // 关闭弹框回调  
    onClose: { type: Function, default: null },  
}
  • 弹窗模板template
<template>  
    <!-- #ifdef APP-NVUE -->  
    <view v-if="opts.visible" class="ua__popup" :class="{'ua__popup-closed': closeAnim}">  
    <!-- #endif -->  
    <!-- #ifndef APP-NVUE -->  
    <view v-show="opts.visible" class="ua__popup" :class="{'ua__popup-closed': closeAnim}">  
    <!-- #endif -->  
        <!-- 遮罩层 -->  
        <view v-if="opts.shade && opts.shade!='false'" class="uapopup__overlay" @touchstart="handleShadeClick" :style="{'opacity': opts.opacity >= 0 ? opts.opacity : '', 'z-index': oIndex-1}"></view>  
        <!-- 窗口层 -->  
        <view class="uapopup__wrap" :style="{'z-index': oIndex}">  
            <view class="uapopup__child" :id="''+uuid" :class="[''+opts.anim, opts.type&&'popui__'+opts.type, opts.round&&'round', opts.position]" :style="[opts.follow&&positionStyle, opts.customStyle]">  
                <!-- //标题 -->  
                <view v-if="opts.title || $slots.title" class="uapopup__title">  
                    <template v-if="$slots.title"><slot name="title" /></template>  
                    <rich-text v-else :nodes="opts.title"></rich-text>  
                </view>  

                <!-- //toast -->  
                <!-- <view v-if="opts.type=='toast'&&opts.icon" class="toast__icons" :class="['toast'+opts.icon]" :style="{'background-image': `url(${toastIcon[opts.icon]})`}"></view> -->  
                <image v-if="opts.type=='toast'&&opts.icon" class="toast__icons" :class="['toast'+opts.icon]" :src="toastIcon[opts.icon]" mode="widthFix"></image>  
                <!-- //内容 -->  
                <view v-if="opts.content || $slots.content" class="uapopup__content">  
                    <template v-if="$slots.content"><slot name="content" /></template>  
                    <rich-text v-else :nodes="opts.content"></rich-text>  
                </view>  
                <slot />  

                <!-- //按钮组 -->  
                <view v-if="opts.btns" class="uapopup__actions">  
                    <rich-text v-for="(btn,index) in opts.btns" :key="index" class="btn" :class="{'disabled': btn.disabled}" :style="btn.style" @click="handleBtnClick($event, index)" :nodes="btn.text"></rich-text>  
                </view>  

                <!-- //关闭按钮 -->  
                <view v-if="opts.xclose" class="uapopup__xclose" :class="opts.xposition" :style="{'color': opts.xcolor}" @click="close"></view>  
            </view>  
        </view>  
    </view>  
</template>
  • 核心逻辑处理
<script>  
    /**  
     * @Desc     uniapp跨端自定义popup组件  
     * @Time     andy by 2021/7/10  
     * @About    Q:282310962  wx:xy190310  
     */  

    let index = 0  
    export default {  
        ...  
        data() {  
            return {  
                // 混入props参数,处理函数式调用  
                opts: {  
                    visible: false,  
                },  
                toastIcon: {  
                    ...  
                },  
                closeAnim: false,  
                oIndex: 202107,  
                timer: null,  
                // 长按定位初始化(避免弹框跳动闪烁)  
                positionStyle: { position: 'absolute', left: '-999px', top: '-999px' },  
            }  
        },  
        watch: {  
            value(val) {  
                const type = val ? 'open' : 'close'  
                this[type]()  
            }  
        },  
        computed: {  
            uuid() {  
                return Math.floor(Math.random() * 10000)  
            },  
        },  
        methods: {  
            // 打开弹框  
            open(options) {  
                if(this.opts.visible) return  
                this.opts = Object.assign({}, this.$props, options)  
                this.opts.visible = true  

                // nvue 的各组件在安卓端默认是透明的,如果不设置background-color,可能会导致出现重影的问题  
                // #ifdef APP-NVUE  
                if(!this.opts.customStyle['background'] && !this.opts.customStyle['background-color']) {  
                    this.opts.customStyle['background'] = '#fff'  
                }  
                // #endif  

                let _index = ++index  
                this.oIndex = _index + parseInt(this.opts.zIndex)  

                this.$emit('open')  
                typeof this.opts.onOpen === 'function' && this.opts.onOpen()  

                // 长按处理  
                if(this.opts.follow) {  
                    ...  
                }  

                ...  
            },  
            // 关闭弹框  
            close() {  
                if(!this.opts.visible) return  

                this.closeAnim = true  
                setTimeout(() => {  
                    this.opts.visible = false  
                    this.closeAnim = false  

                    this.$emit('input', false)  
                    this.$emit('close')  
                    typeof this.opts.onClose === 'function' && this.opts.onClose()  

                    this.timer && clearTimeout(this.timer)  
                    delete this.timer  
                }, 200)  
            },  

            ...  

            // 获取dom宽高  
            getDom(id) {  
                return new Promise((resolve, inject) => {  
                    uni.createSelectorQuery().in(this).select('#' + id).fields({  
                        size: true,  
                    }, data => {  
                        resolve(data)  
                    }).exec()  
                })  
            },  

            // 自适应坐标点  
            getPos(x, y, ow, oh, winW, winH) {  
                let l = (x + ow) > winW ? x - ow : x;  
                let t = (y + oh) > winH ? y - oh : y;  
                return [l, t];  
            },  
        }  
    }  
</script>

基本可通过组件式+函数式组合开发出一些复杂的弹窗应用场景。

okey,基于uniapp开发自定义弹窗组件就分享到这里了。希望对大家有些帮助哈~~✍✍

链接:https://juejin.cn/post/6977298346905960456/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

继续阅读 »

基于uni-app开发兼容全端自定义弹出框ua-popup插件,可完美运行在h5、小程序及app端。

uaPopup 一款整合了msg信息框、alert提示框、dialog对话框、actionSheet底部面板框、toast轻提示框、android/ios弹窗等多种弹窗效果。可以自定义弹窗样式及按钮样式和事件、多个弹窗嵌套显示,支持自定义插槽模板内容。

如下图:h5/小程序/app端效果
img

可覆盖在Nvue原生页面video组件之上

img

引入组件

uapopup 支持全局main.js引入或页面单独引入使用。

import UAPopup from './components/ua-popup/index.vue'  
Vue.component('ua-popup', UAPopup)

自hbuilderx2.5起 支持easycom组件模式。根据使用习惯,也可以改为components/ua-popup/ua-popup.vue方式,系统会自定义识别组件,无需再手动注册引入。

使用组件

ua-popup支持组件写法和函数式写法来调用组件。

  • 组件式调用
<!-- msg提示 -->  
<ua-popup v-model="showMsg" anim="fadeIn" content="上善若水,水利万物而不争" shadeClose="false" time="3" />  

<!-- 询问框 -->  
<ua-popup v-model="showConfirm" shadeClose="false" title="标题" xclose z-index="2001"  
    content="<div style='color:#ff557f;padding:20px 40px;'>一切都将一去杳然,任何人都无法将其捕获。</div>"  
    :btns="[  
        {text: '取消', click: hideConfirm},  
        {text: '确定', style: 'color:#00aa00;', click: handleInfo},  
    ]"  
/>
  • 函数式调用
// 函数式多层嵌套  
handleInfo() {  
    let $ua = this.$refs.uapopup  
    let $toast = this.$refs.uatoast  
    $ua.open({  
        content: '人生漫漫,且行且珍惜',  
        customStyle: {'background-color': 'rgba(170, 0, 127, 0.6)', 'color': '#fff'},  
        time: 3,  
        onClose() {  
            $ua.open({  
                type: 'android',  
                content: '<div style="color:#aa007f">预测未来的最好办法是自己亲手创造未来</div>',  
                customStyle: {'width': '200px'},  
                zIndex: 202120,  
                btns: [  
                    {  
                        text: 'close', click() {  
                            $ua.close()  
                        }  
                    },  
                    {  
                        text: 'Get一下',  
                        style: 'color:#00aa00;',  
                        click() {  
                            $toast.open({  
                                type: 'toast',  
                                icon: 'loading',  
                                content: '请稍后...',  
                                opacity: .2,  
                                time: 2,  
                                zIndex: 202125,  
                            })  
                        }  
                    }  
                ]  
            })  
        }  
    })  
}

img

img

编码开发

  • 支持如下20+参数自定义配置。
props: {  
    value: { type: Boolean, default: false },  
    title: String,  
    content: String,  
    type: String,  
    customStyle: { type: Object, default: null },  
    icon: String,  
    shade: { type: [Boolean, String], default: true },  
    shadeClose: { type: [Boolean, String], default: true },  
    opacity: { type: [Number, String], default: '' },  
    round: Boolean,  
    xclose: Boolean,  
    xposition: { type: String, default: 'right' },  
    xcolor: { type: String, default: '#333' },  
    anim: { type: String, default: 'scaleIn' },  
    position: String,  
    follow: { type: Array, default: null },  
    time: { type: [Number, String], default: 0 },  
    zIndex: { type: [Number, String], default: '202107' },  
    btns: {  
        type: Array, default: null  
    },  
    // 打开弹框回调  
    onOpen: { type: Function, default: null },  
    // 关闭弹框回调  
    onClose: { type: Function, default: null },  
}
  • 弹窗模板template
<template>  
    <!-- #ifdef APP-NVUE -->  
    <view v-if="opts.visible" class="ua__popup" :class="{'ua__popup-closed': closeAnim}">  
    <!-- #endif -->  
    <!-- #ifndef APP-NVUE -->  
    <view v-show="opts.visible" class="ua__popup" :class="{'ua__popup-closed': closeAnim}">  
    <!-- #endif -->  
        <!-- 遮罩层 -->  
        <view v-if="opts.shade && opts.shade!='false'" class="uapopup__overlay" @touchstart="handleShadeClick" :style="{'opacity': opts.opacity >= 0 ? opts.opacity : '', 'z-index': oIndex-1}"></view>  
        <!-- 窗口层 -->  
        <view class="uapopup__wrap" :style="{'z-index': oIndex}">  
            <view class="uapopup__child" :id="''+uuid" :class="[''+opts.anim, opts.type&&'popui__'+opts.type, opts.round&&'round', opts.position]" :style="[opts.follow&&positionStyle, opts.customStyle]">  
                <!-- //标题 -->  
                <view v-if="opts.title || $slots.title" class="uapopup__title">  
                    <template v-if="$slots.title"><slot name="title" /></template>  
                    <rich-text v-else :nodes="opts.title"></rich-text>  
                </view>  

                <!-- //toast -->  
                <!-- <view v-if="opts.type=='toast'&&opts.icon" class="toast__icons" :class="['toast'+opts.icon]" :style="{'background-image': `url(${toastIcon[opts.icon]})`}"></view> -->  
                <image v-if="opts.type=='toast'&&opts.icon" class="toast__icons" :class="['toast'+opts.icon]" :src="toastIcon[opts.icon]" mode="widthFix"></image>  
                <!-- //内容 -->  
                <view v-if="opts.content || $slots.content" class="uapopup__content">  
                    <template v-if="$slots.content"><slot name="content" /></template>  
                    <rich-text v-else :nodes="opts.content"></rich-text>  
                </view>  
                <slot />  

                <!-- //按钮组 -->  
                <view v-if="opts.btns" class="uapopup__actions">  
                    <rich-text v-for="(btn,index) in opts.btns" :key="index" class="btn" :class="{'disabled': btn.disabled}" :style="btn.style" @click="handleBtnClick($event, index)" :nodes="btn.text"></rich-text>  
                </view>  

                <!-- //关闭按钮 -->  
                <view v-if="opts.xclose" class="uapopup__xclose" :class="opts.xposition" :style="{'color': opts.xcolor}" @click="close"></view>  
            </view>  
        </view>  
    </view>  
</template>
  • 核心逻辑处理
<script>  
    /**  
     * @Desc     uniapp跨端自定义popup组件  
     * @Time     andy by 2021/7/10  
     * @About    Q:282310962  wx:xy190310  
     */  

    let index = 0  
    export default {  
        ...  
        data() {  
            return {  
                // 混入props参数,处理函数式调用  
                opts: {  
                    visible: false,  
                },  
                toastIcon: {  
                    ...  
                },  
                closeAnim: false,  
                oIndex: 202107,  
                timer: null,  
                // 长按定位初始化(避免弹框跳动闪烁)  
                positionStyle: { position: 'absolute', left: '-999px', top: '-999px' },  
            }  
        },  
        watch: {  
            value(val) {  
                const type = val ? 'open' : 'close'  
                this[type]()  
            }  
        },  
        computed: {  
            uuid() {  
                return Math.floor(Math.random() * 10000)  
            },  
        },  
        methods: {  
            // 打开弹框  
            open(options) {  
                if(this.opts.visible) return  
                this.opts = Object.assign({}, this.$props, options)  
                this.opts.visible = true  

                // nvue 的各组件在安卓端默认是透明的,如果不设置background-color,可能会导致出现重影的问题  
                // #ifdef APP-NVUE  
                if(!this.opts.customStyle['background'] && !this.opts.customStyle['background-color']) {  
                    this.opts.customStyle['background'] = '#fff'  
                }  
                // #endif  

                let _index = ++index  
                this.oIndex = _index + parseInt(this.opts.zIndex)  

                this.$emit('open')  
                typeof this.opts.onOpen === 'function' && this.opts.onOpen()  

                // 长按处理  
                if(this.opts.follow) {  
                    ...  
                }  

                ...  
            },  
            // 关闭弹框  
            close() {  
                if(!this.opts.visible) return  

                this.closeAnim = true  
                setTimeout(() => {  
                    this.opts.visible = false  
                    this.closeAnim = false  

                    this.$emit('input', false)  
                    this.$emit('close')  
                    typeof this.opts.onClose === 'function' && this.opts.onClose()  

                    this.timer && clearTimeout(this.timer)  
                    delete this.timer  
                }, 200)  
            },  

            ...  

            // 获取dom宽高  
            getDom(id) {  
                return new Promise((resolve, inject) => {  
                    uni.createSelectorQuery().in(this).select('#' + id).fields({  
                        size: true,  
                    }, data => {  
                        resolve(data)  
                    }).exec()  
                })  
            },  

            // 自适应坐标点  
            getPos(x, y, ow, oh, winW, winH) {  
                let l = (x + ow) > winW ? x - ow : x;  
                let t = (y + oh) > winH ? y - oh : y;  
                return [l, t];  
            },  
        }  
    }  
</script>

基本可通过组件式+函数式组合开发出一些复杂的弹窗应用场景。

okey,基于uniapp开发自定义弹窗组件就分享到这里了。希望对大家有些帮助哈~~✍✍

链接:https://juejin.cn/post/6977298346905960456/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

收起阅读 »

加油系统有哪些功能?

小程序

1.话费93折充值:字面意思,话费充值100元,实际消费93元。有公众号粉丝告诉我,他昨天找到一个90折的,今天又找到一个88折的,当然这里只是以93折为例,市面上大多是93折的,90折到95折的也都有,88折这种不多说。
2.影视、音乐会员:很多加油软件上面有超低价的影视、音乐会员,有的比官方渠道要便宜一大半。
3.洗车:有的平台会显示同城洗车店,上面的价格也是相当便宜,基本在外面洗1次,软件上面可以洗3次。
4.旅游卡:旅游卡上面包含的旅游项目很多,国内的、国外的都有,但一般都是名气比较高的地区,如果你想去但线下没有渠道,这上面的也要比线下自己找的要便宜好多。
5.积分、商城:你会发现平时在淘宝、京东能买到的在这些软件上面也能买到,甚至也可以以加油金的形式进行抵扣一部分。
6.生活缴费:生活缴费包括我们常用的水费、电费、燃气费、物业费、宽带、固话、暖气、有线电视等,但这些缴费一般没有优惠,只是提供一个便捷的服务,如果你发现有些软件上面有限时优惠,也是可以薅一薅的。
7.外卖券:外卖券可以说近也火起来了,以前很多人都不知道外卖券的存在,现在只要点餐,件事情就是找公众号或者APP等各种资源领券下单。
8.吃喝玩乐:都是自己周边的一些优惠团购券,涵盖吃、喝、玩、乐各种优惠券。

继续阅读 »

1.话费93折充值:字面意思,话费充值100元,实际消费93元。有公众号粉丝告诉我,他昨天找到一个90折的,今天又找到一个88折的,当然这里只是以93折为例,市面上大多是93折的,90折到95折的也都有,88折这种不多说。
2.影视、音乐会员:很多加油软件上面有超低价的影视、音乐会员,有的比官方渠道要便宜一大半。
3.洗车:有的平台会显示同城洗车店,上面的价格也是相当便宜,基本在外面洗1次,软件上面可以洗3次。
4.旅游卡:旅游卡上面包含的旅游项目很多,国内的、国外的都有,但一般都是名气比较高的地区,如果你想去但线下没有渠道,这上面的也要比线下自己找的要便宜好多。
5.积分、商城:你会发现平时在淘宝、京东能买到的在这些软件上面也能买到,甚至也可以以加油金的形式进行抵扣一部分。
6.生活缴费:生活缴费包括我们常用的水费、电费、燃气费、物业费、宽带、固话、暖气、有线电视等,但这些缴费一般没有优惠,只是提供一个便捷的服务,如果你发现有些软件上面有限时优惠,也是可以薅一薅的。
7.外卖券:外卖券可以说近也火起来了,以前很多人都不知道外卖券的存在,现在只要点餐,件事情就是找公众号或者APP等各种资源领券下单。
8.吃喝玩乐:都是自己周边的一些优惠团购券,涵盖吃、喝、玩、乐各种优惠券。

收起阅读 »

走向商业闭环的加油软件

小程序

目前市面上已经有很多加油优惠软件,很多车主都已经在用这样的软件,也有很多车主并不知道这样软件的存在,那么你对加油优惠软件到底了解多少?一篇文章带你深入了解加油软件。

走向商业闭环的加油软件

一、加油优惠软件存在的意义是什么?

车主在软件上面可以清晰地看到自己所在城市乃至全国加油站的油价,并且可以选择离自己家较近且优惠力度较大的加油站进行加油。每次加油200块钱,实际支付175元左右,还是很划算的,省下来的钱买肉吃还是很香的。
软件所有者通过通过这款软件可以0成本招代理、招商户,将加油优惠卡以极低的价格推广出去,以达到引流变现的效果。
代理商以极低的价格从软件商这里拿加油优惠卡,通过地推的形式将这种加油卡加价卖给实体店。
实体店通过加油卡引流、刺激消费,通常都是以,全场消费满200元赠送200元礼品加油卡,消费满500元赠送500,消费越多,赠送越多。
走向商业闭环的加油软件
二、除了加油优惠还有哪些优惠?

单靠一个加油优惠还不足以牢牢锁住用户,那么除了加油优惠,还有其他什么优惠模式?

话费93折充值:字面意思,话费充值100元,实际消费93元。有公众号粉丝告诉我,他昨天找到一个90折的,今天又找到一个88折的,当然这里只是以93折为例,市面上大多是93折的,90折到95折的也都有,88折这种不多说。
影视、音乐会员:很多加油软件上面有超低价的影视、音乐会员,有的比官方渠道要便宜一大半。
洗车:有的平台会显示同城洗车店,上面的价格也是相当便宜,基本在外面洗1次,软件上面可以洗3次。
旅游卡:旅游卡上面包含的旅游项目很多,国内的、国外的都有,但一般都是名气比较高的地区,如果你想去但线下没有渠道,这上面的也要比线下自己找的要便宜好多。
积分、商城:你会发现平时在淘宝、京东能买到的在这些软件上面也能买到,甚至也可以以加油金的形式进行抵扣一部分。
生活缴费:生活缴费包括我们常用的水费、电费、燃气费、物业费、宽带、固话、暖气、有线电视等,但这些缴费一般没有优惠,只是提供一个便捷的服务,如果你发现有些软件上面有限时优惠,也是可以薅一薅的。
外卖券:外卖券可以说最近也火起来了,以前很多人都不知道外卖券的存在,现在只要点餐,第一件事情就是找公众号或者APP等各种资源领券下单。
吃喝玩乐:都是自己周边的一些优惠团购券,涵盖吃、喝、玩、乐各种优惠券。
走向商业闭环的加油软件
三、总结几个公众号粉丝经常问到问题

  1. 加油为什么可以优惠?

加油是这些软件对接的一些第三方加油接口,接口是第三方公司整合起来的加油数据,只要是数据里有的油站都可以享受加油优惠,优惠力度也不相同。

  1. 我想做这么一款软件,应该用哪个接口?有什么区别?

市面上的接口有团油、小桔、易加油。团油整合的油站数量最多,全国有7万家左右,小桔整合的较少有3万家左右,团油优惠力度比小桔稍微低一点,个别油站优惠力度相差较大。申请团油接口每年有1万元的服务费,小桔接口申请免费。对接易加油的平台较少。

  1. 为什么我用的软件上面优惠力度很小几乎没有?

油站具体优惠金额还是油站自己控制的,可能昨天优惠力度较大,今天心情不好,就不想优惠了,这个你只要找到优惠的油站加油就可以了,不用纠结这个,只要知道数据是油站可以调控的。

  1. 话费、影视、音乐优惠可靠吗?

可靠,和加油接口一样,这些也是找的接口方,或者他们自己找的渠道,可以放心用。

走向商业闭环的加油软件

加油系统在这样一个大的环境下势必会走向一个集各种刚需实用优惠为一体的模式,在这样一个加油系统众多的环境下,有没有会成为黑马的存在,一统国内市场呢?亦或者形成三足鼎立的形态?让我们拭目以待吧!

继续阅读 »

目前市面上已经有很多加油优惠软件,很多车主都已经在用这样的软件,也有很多车主并不知道这样软件的存在,那么你对加油优惠软件到底了解多少?一篇文章带你深入了解加油软件。

走向商业闭环的加油软件

一、加油优惠软件存在的意义是什么?

车主在软件上面可以清晰地看到自己所在城市乃至全国加油站的油价,并且可以选择离自己家较近且优惠力度较大的加油站进行加油。每次加油200块钱,实际支付175元左右,还是很划算的,省下来的钱买肉吃还是很香的。
软件所有者通过通过这款软件可以0成本招代理、招商户,将加油优惠卡以极低的价格推广出去,以达到引流变现的效果。
代理商以极低的价格从软件商这里拿加油优惠卡,通过地推的形式将这种加油卡加价卖给实体店。
实体店通过加油卡引流、刺激消费,通常都是以,全场消费满200元赠送200元礼品加油卡,消费满500元赠送500,消费越多,赠送越多。
走向商业闭环的加油软件
二、除了加油优惠还有哪些优惠?

单靠一个加油优惠还不足以牢牢锁住用户,那么除了加油优惠,还有其他什么优惠模式?

话费93折充值:字面意思,话费充值100元,实际消费93元。有公众号粉丝告诉我,他昨天找到一个90折的,今天又找到一个88折的,当然这里只是以93折为例,市面上大多是93折的,90折到95折的也都有,88折这种不多说。
影视、音乐会员:很多加油软件上面有超低价的影视、音乐会员,有的比官方渠道要便宜一大半。
洗车:有的平台会显示同城洗车店,上面的价格也是相当便宜,基本在外面洗1次,软件上面可以洗3次。
旅游卡:旅游卡上面包含的旅游项目很多,国内的、国外的都有,但一般都是名气比较高的地区,如果你想去但线下没有渠道,这上面的也要比线下自己找的要便宜好多。
积分、商城:你会发现平时在淘宝、京东能买到的在这些软件上面也能买到,甚至也可以以加油金的形式进行抵扣一部分。
生活缴费:生活缴费包括我们常用的水费、电费、燃气费、物业费、宽带、固话、暖气、有线电视等,但这些缴费一般没有优惠,只是提供一个便捷的服务,如果你发现有些软件上面有限时优惠,也是可以薅一薅的。
外卖券:外卖券可以说最近也火起来了,以前很多人都不知道外卖券的存在,现在只要点餐,第一件事情就是找公众号或者APP等各种资源领券下单。
吃喝玩乐:都是自己周边的一些优惠团购券,涵盖吃、喝、玩、乐各种优惠券。
走向商业闭环的加油软件
三、总结几个公众号粉丝经常问到问题

  1. 加油为什么可以优惠?

加油是这些软件对接的一些第三方加油接口,接口是第三方公司整合起来的加油数据,只要是数据里有的油站都可以享受加油优惠,优惠力度也不相同。

  1. 我想做这么一款软件,应该用哪个接口?有什么区别?

市面上的接口有团油、小桔、易加油。团油整合的油站数量最多,全国有7万家左右,小桔整合的较少有3万家左右,团油优惠力度比小桔稍微低一点,个别油站优惠力度相差较大。申请团油接口每年有1万元的服务费,小桔接口申请免费。对接易加油的平台较少。

  1. 为什么我用的软件上面优惠力度很小几乎没有?

油站具体优惠金额还是油站自己控制的,可能昨天优惠力度较大,今天心情不好,就不想优惠了,这个你只要找到优惠的油站加油就可以了,不用纠结这个,只要知道数据是油站可以调控的。

  1. 话费、影视、音乐优惠可靠吗?

可靠,和加油接口一样,这些也是找的接口方,或者他们自己找的渠道,可以放心用。

走向商业闭环的加油软件

加油系统在这样一个大的环境下势必会走向一个集各种刚需实用优惠为一体的模式,在这样一个加油系统众多的环境下,有没有会成为黑马的存在,一统国内市场呢?亦或者形成三足鼎立的形态?让我们拭目以待吧!

收起阅读 »

uniapp真正实现App静默安装

uniapp静默更新

注意:这篇文章仅针对有Root权限的Android设备实现静默更新

先来看看uniapp端的静默更新效果:

什么鬼,需要我自己点算个什么静默更新....

于是就想到用Android原生实现静默更新再搞个插件什么的在uniapp上运行

一、准备开发环境
JAVA环境 jdk1.8
Android Studio
App离线SDK下载:请下载2.9.8 版本的android平台SDK
官网SDK解压后如下图

二、导入项目
导入uni插件原生项目 UniPlugin-Hello-AS工程请在App离线SDK中查找
点击Android Studio菜单选项File—>New—>Import Project。

三、创建插件Library

选择Android Library

输入 Library名称Update点击finish
然后在app目录下的build.gradle下引入 Update

将app libs目录下的 uniapp-v8-release.aar包(名字可能不一样)复制到 Update libs下

然后修改modle Update中的build.gradle文件 引入aar包 点击右上角同步即可

四、然后在modle目录下创建SilentInstallation类集成UniMoudle

package android.laboreryao.update;

import android.util.Log;
import android.widget.Toast;

import com.taobao.weex.bridge.JSCallback;

import java.io.File;

import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.common.UniModule;

/**

  • 功能介绍:静默安装<br/>
  • 调用方式: / <br/>
  • <p/>
  • 作 者: LaborerYao - 228598641@qq.com <br/>
  • 创建电脑: <br/>
  • 创建时间: 2021/6/25 18:01 <br/>
  • 最后编辑: 2021/6/25 - yyl
  • @author LaborerYao
    */
    public class SilentInstallation extends UniModule {
    /**

    • 静默安装
    • @param apkPath
    • @param jsCallback result true 安装成功 false 失败
      */
      @UniJSMethod(uiThread = true)
      public void UpdateLotteryMachineApp(String apkPath, JSCallback jsCallback) {
      Log.e("LaborerYao", "Update!!!apkPath==" apkPath);
      if (!isRoot()) {
      Toast.makeText(mWXSDKInstance.getContext(), "没有ROOT权限,不能使用静默安装", Toast.LENGTH_SHORT).show();
      jsCallback.invoke(false);
      }
      SilentInstall installHelper = new SilentInstall();
      final boolean result = installHelper.install(apkPath);
      jsCallback.invoke(result);
      }

    /**

    • 判断手机是否拥有Root权限。
    • @return 有root权限返回true,否则返回false。
      */
      public boolean isRoot() {
      boolean bool = false;
      try {
      bool = new File("/system/bin/su").exists() || new File("/system/xbin/su").exists();
      } catch (Exception e) {
      e.printStackTrace();
      }
      return bool;
      }
      }

五、创建静默安装实现类,调用"pm install -r"命令进行静默安装
package android.laboreryao.update;

/**

  • 功能介绍: <br/>
  • 调用方式: / <br/>
  • <p/>
  • 作 者: LaborerYao - 228598641@qq.com <br/>
  • 创建电脑: <br/>
  • 创建时间: 2021/6/25 14:49 <br/>
  • 最后编辑: 2021/6/25 - yyl
  • @author LaborerYao
    */

import android.util.Log;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class SilentInstall {

/**  
 * 执行具体的静默安装逻辑,需要手机ROOT。  
 * @param apkPath  
 *          要安装的apk文件的路径  
 * @return 安装成功返回true,安装失败返回false。  
 */  
public boolean install(String apkPath) {  
    boolean result = false;  
    DataOutputStream dataOutputStream = null;  
    BufferedReader errorStream = null;  
    try {  
        // 申请su权限  
        Process process = Runtime.getRuntime().exec("su");  
        dataOutputStream = new DataOutputStream(process.getOutputStream());  
        // 执行pm install命令  
        String command = "pm install -r "   apkPath   "\n";  
        dataOutputStream.write(command.getBytes(Charset.forName("utf-8")));  
        dataOutputStream.flush();  
        dataOutputStream.writeBytes("exit\n");  
        dataOutputStream.flush();  
        process.waitFor();  
        errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));  
        String msg = "";  
        String line;  
        // 读取命令的执行结果  
        while ((line = errorStream.readLine()) != null) {  
            msg  = line;  
        }  
        Log.d("TAG", "install msg is "   msg);  
        // 如果执行结果中包含Failure字样就认为是安装失败,否则就认为安装成功  
        if (!msg.contains("Failure")) {  
            result = true;  
        }  
    } catch (Exception e) {  
        Log.e("TAG", e.getMessage(), e);  
    } finally {  
        try {  
            if (dataOutputStream != null) {  
                dataOutputStream.close();  
            }  
            if (errorStream != null) {  
                errorStream.close();  
            }  
        } catch (IOException e) {  
            Log.e("TAG", e.getMessage(), e);  
        }  
    }  
    return result;  
}  

}

六、创建BootBroadcastReceiver 广播用来监听apk安装完成自动打开
package android.laboreryao.update;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**

  • 功能介绍:自启动Receiver<br/>
  • 调用方式: / <br/>
  • <p/>
  • 作 者: LaborerYao - 228598641@qq.com <br/>
  • 创建电脑: MaiyuanAndroid2 <br/>
  • 创建时间: 2021/6/25 18:01 <br/>
  • 最后编辑: 2021/6/25 - yyl
  • @author LaborerYao
    */
    public class BootBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "sjft";

    public static final String EXTRA_VOLUME_STATE =
    "android.os.storage.extra.VOLUME_STATE";

    public static final int STATE_UNMOUNTED = 0;
    public static final int STATE_CHECKING = 1;
    public static final int STATE_MOUNTED = 2;
    public static final int STATE_MOUNTED_READ_ONLY = 3;
    public static final int STATE_FORMATTING = 4;
    public static final int STATE_EJECTING = 5;
    public static final int STATE_UNMOUNTABLE = 6;
    public static final int STATE_REMOVED = 7;
    public static final int STATE_BAD_REMOVAL = 8;

    @Override
    public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    String action = intent.getAction();
    if (action.equals("android.intent.action.PACKAGE_REPLACED")) {
    String packageName = intent.getData().getSchemeSpecificPart();
    Log.v(TAG, "BootBroadcastReceiver packageName:" packageName);
    if (context.getPackageName().equals(packageName)) {
    //Intent launchIntent = new Intent(context, MainActivity.class);//重新启动应用
    //此处如果不想写死启动的Activity,也可以通过如下方法获取默认的启动Activity
    Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
    launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(launchIntent);
    }
    }
    }
    }
    七、在AndroidManifest注册广播 并添加对应权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="android.laboreryao.update">

<uses-permission  
    android:name="android.permission.INSTALL_PACKAGES"  
    tools:ignore="ProtectedPermissions"/>  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

<application>  
    <receiver android:name=".BootBroadcastReceiver">  
        <intent-filter>  
            <action android:name="android.intent.action.PACKAGE_ADDED"/>  
            <action android:name="android.intent.action.PACKAGE_REPLACED"/>  
            <action android:name="android.intent.action.PACKAGE_REMOVED"/>  

            <data android:scheme="package"/>  
        </intent-filter>  
    </receiver>  
</application>  

</manifest>

八、打包插件arr包

九、将arr包放到uniapp项目 配置本地插件 打自定义基座 使用基座调试

继续阅读 »

uniapp静默更新

注意:这篇文章仅针对有Root权限的Android设备实现静默更新

先来看看uniapp端的静默更新效果:

什么鬼,需要我自己点算个什么静默更新....

于是就想到用Android原生实现静默更新再搞个插件什么的在uniapp上运行

一、准备开发环境
JAVA环境 jdk1.8
Android Studio
App离线SDK下载:请下载2.9.8 版本的android平台SDK
官网SDK解压后如下图

二、导入项目
导入uni插件原生项目 UniPlugin-Hello-AS工程请在App离线SDK中查找
点击Android Studio菜单选项File—>New—>Import Project。

三、创建插件Library

选择Android Library

输入 Library名称Update点击finish
然后在app目录下的build.gradle下引入 Update

将app libs目录下的 uniapp-v8-release.aar包(名字可能不一样)复制到 Update libs下

然后修改modle Update中的build.gradle文件 引入aar包 点击右上角同步即可

四、然后在modle目录下创建SilentInstallation类集成UniMoudle

package android.laboreryao.update;

import android.util.Log;
import android.widget.Toast;

import com.taobao.weex.bridge.JSCallback;

import java.io.File;

import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.common.UniModule;

/**

  • 功能介绍:静默安装<br/>
  • 调用方式: / <br/>
  • <p/>
  • 作 者: LaborerYao - 228598641@qq.com <br/>
  • 创建电脑: <br/>
  • 创建时间: 2021/6/25 18:01 <br/>
  • 最后编辑: 2021/6/25 - yyl
  • @author LaborerYao
    */
    public class SilentInstallation extends UniModule {
    /**

    • 静默安装
    • @param apkPath
    • @param jsCallback result true 安装成功 false 失败
      */
      @UniJSMethod(uiThread = true)
      public void UpdateLotteryMachineApp(String apkPath, JSCallback jsCallback) {
      Log.e("LaborerYao", "Update!!!apkPath==" apkPath);
      if (!isRoot()) {
      Toast.makeText(mWXSDKInstance.getContext(), "没有ROOT权限,不能使用静默安装", Toast.LENGTH_SHORT).show();
      jsCallback.invoke(false);
      }
      SilentInstall installHelper = new SilentInstall();
      final boolean result = installHelper.install(apkPath);
      jsCallback.invoke(result);
      }

    /**

    • 判断手机是否拥有Root权限。
    • @return 有root权限返回true,否则返回false。
      */
      public boolean isRoot() {
      boolean bool = false;
      try {
      bool = new File("/system/bin/su").exists() || new File("/system/xbin/su").exists();
      } catch (Exception e) {
      e.printStackTrace();
      }
      return bool;
      }
      }

五、创建静默安装实现类,调用"pm install -r"命令进行静默安装
package android.laboreryao.update;

/**

  • 功能介绍: <br/>
  • 调用方式: / <br/>
  • <p/>
  • 作 者: LaborerYao - 228598641@qq.com <br/>
  • 创建电脑: <br/>
  • 创建时间: 2021/6/25 14:49 <br/>
  • 最后编辑: 2021/6/25 - yyl
  • @author LaborerYao
    */

import android.util.Log;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class SilentInstall {

/**  
 * 执行具体的静默安装逻辑,需要手机ROOT。  
 * @param apkPath  
 *          要安装的apk文件的路径  
 * @return 安装成功返回true,安装失败返回false。  
 */  
public boolean install(String apkPath) {  
    boolean result = false;  
    DataOutputStream dataOutputStream = null;  
    BufferedReader errorStream = null;  
    try {  
        // 申请su权限  
        Process process = Runtime.getRuntime().exec("su");  
        dataOutputStream = new DataOutputStream(process.getOutputStream());  
        // 执行pm install命令  
        String command = "pm install -r "   apkPath   "\n";  
        dataOutputStream.write(command.getBytes(Charset.forName("utf-8")));  
        dataOutputStream.flush();  
        dataOutputStream.writeBytes("exit\n");  
        dataOutputStream.flush();  
        process.waitFor();  
        errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));  
        String msg = "";  
        String line;  
        // 读取命令的执行结果  
        while ((line = errorStream.readLine()) != null) {  
            msg  = line;  
        }  
        Log.d("TAG", "install msg is "   msg);  
        // 如果执行结果中包含Failure字样就认为是安装失败,否则就认为安装成功  
        if (!msg.contains("Failure")) {  
            result = true;  
        }  
    } catch (Exception e) {  
        Log.e("TAG", e.getMessage(), e);  
    } finally {  
        try {  
            if (dataOutputStream != null) {  
                dataOutputStream.close();  
            }  
            if (errorStream != null) {  
                errorStream.close();  
            }  
        } catch (IOException e) {  
            Log.e("TAG", e.getMessage(), e);  
        }  
    }  
    return result;  
}  

}

六、创建BootBroadcastReceiver 广播用来监听apk安装完成自动打开
package android.laboreryao.update;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**

  • 功能介绍:自启动Receiver<br/>
  • 调用方式: / <br/>
  • <p/>
  • 作 者: LaborerYao - 228598641@qq.com <br/>
  • 创建电脑: MaiyuanAndroid2 <br/>
  • 创建时间: 2021/6/25 18:01 <br/>
  • 最后编辑: 2021/6/25 - yyl
  • @author LaborerYao
    */
    public class BootBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "sjft";

    public static final String EXTRA_VOLUME_STATE =
    "android.os.storage.extra.VOLUME_STATE";

    public static final int STATE_UNMOUNTED = 0;
    public static final int STATE_CHECKING = 1;
    public static final int STATE_MOUNTED = 2;
    public static final int STATE_MOUNTED_READ_ONLY = 3;
    public static final int STATE_FORMATTING = 4;
    public static final int STATE_EJECTING = 5;
    public static final int STATE_UNMOUNTABLE = 6;
    public static final int STATE_REMOVED = 7;
    public static final int STATE_BAD_REMOVAL = 8;

    @Override
    public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    String action = intent.getAction();
    if (action.equals("android.intent.action.PACKAGE_REPLACED")) {
    String packageName = intent.getData().getSchemeSpecificPart();
    Log.v(TAG, "BootBroadcastReceiver packageName:" packageName);
    if (context.getPackageName().equals(packageName)) {
    //Intent launchIntent = new Intent(context, MainActivity.class);//重新启动应用
    //此处如果不想写死启动的Activity,也可以通过如下方法获取默认的启动Activity
    Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
    launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(launchIntent);
    }
    }
    }
    }
    七、在AndroidManifest注册广播 并添加对应权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="android.laboreryao.update">

<uses-permission  
    android:name="android.permission.INSTALL_PACKAGES"  
    tools:ignore="ProtectedPermissions"/>  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

<application>  
    <receiver android:name=".BootBroadcastReceiver">  
        <intent-filter>  
            <action android:name="android.intent.action.PACKAGE_ADDED"/>  
            <action android:name="android.intent.action.PACKAGE_REPLACED"/>  
            <action android:name="android.intent.action.PACKAGE_REMOVED"/>  

            <data android:scheme="package"/>  
        </intent-filter>  
    </receiver>  
</application>  

</manifest>

八、打包插件arr包

九、将arr包放到uniapp项目 配置本地插件 打自定义基座 使用基座调试

收起阅读 »

iOS混淆工具

1593768128247-016fe60b-8853-48fb-8b76-f9f702b83db5.png

中文 | English

前言

机缘巧合偶遇iOS马甲包业务,前期也使用过目前市面上其他得工具,实际效果不太理想。经过大量实践,开发出一款功能齐全的混淆工具。工具的主要功能OC、C++、Swift已封装成Mac应用,其他功能还在封装中,敬请期待。

提示

为了让大家快速上手及对比混淆效果,新建了测试工程confuse_test,大家在实际使用过程中如果遇到问题,欢迎扩展测试工程,请在工程中请注明bug细节,有奖励。
> 1.2.0之前的老版本说明:
> 简介:不涉及语法及编译要求,但是混淆后可能出现局部漏改或者改错,请自行添加至黑名单过滤。
> 适用项目:RN等还未适配的混合项目。
> 使用条件:暂时没法使用,后期重新开放

有问题请及时联系作者,非常感谢。

自述

马甲包的本质:

  1. 阶段一减低重复率 ,本人开发初期的版本和目前市面上的其它工具基本相似,主要是‘名称’全局替换这一个基本的功能
  2. 阶段二减少相似度(相同元素的正态分布),目前该工具经过优化及不断重构已经有了很大的改善,目前基本符合这方面要求,详情见以下功能介绍。事物都有两面性,功能越强大混淆耗时越长,如果你的项目很大,混淆几个小时也是有可能的,请不要见怪,后续持续优化中。

区分工具优劣

其实识别一个工具的优劣,只需看看以下几点:

  1. 能否修改所有的属性、方法,及方法的所有参数名
  2. 修改成员(属性、方法)名称,能否按类区分,还是简单的全局替换
  3. 带block的参数的方法,典型的网络请求,例如:+ (BOOL)post:(NSString )url parameters:(NSDictionary )parameters success:(HttpRequestResponse)success error:(HttpRequestResponse)error;
  4. 方法名和属性名改后的名字的长短(本工具能够保证60~80%的改后名称是常见的一个单词,例如:name、title等且保证不与系统冲突,完全摒弃简单的靠大量单词库堆砌以保证命名的唯一性的做法,真正模拟人工开发)
  5. 修改布局(Frame、Masonry、SDAutoLayout)
  6. 插入的是代码还是‘垃圾’(本工具通过封装网络请求,创建自定义控件,文件之间使用MVC模式关联,彻底告别‘垃圾’,实现以假乱真)。
  7. 更别说“还有谁...”能识别宏、区分继承链等上下文关联内容,智能识别不可修改部分,例如:+ (void)init;- (void)reloadData;基本能改,做到的有几个呢?”
  8. 正常项目(或者第三方库)混淆完基本不报错(除了一些个别语法不严谨造成混淆后报错)
    也欢迎大家使用不同工具混淆测试工程confuse_test或者第三方开源库项目,对比效果。

功能

confuse是一款混淆工具,尽可能模拟人工开发,仿照Xcode部分功能,避免机核4.3、2.1、2.3.1、账号调查等。
目标:模拟人工修改一切能改的地方,这也是为什么本工具只有黑名单没有白名单的原因
详细功能如下(基本功能不做描述,详见其他工具):

已完成

以下功能均支持:

  1. 黑名单(二级)过滤,自由控制每个功能的混淆内容,几乎适应所有项目。
  2. 混淆百分比控制,可以结合自己项目的实际需求,自由调整
  3. 智能名词替换:
    1. 重命名时使用关联类型已有信息+相近语义+类型+部分旧词汇等组合,并且过滤敏感词汇,同时用户也可以自定义敏感词,弃用‘随机单词无脑组合’
    2. 异类同名成员->异类异名成员,异类异名成员->异类同名成员,模拟正常开发。成员指的是方法、属性、函数
  4. 智能识别不可修改部分:通过类型及继承链方式识别系统、第三方、Pod方法,并不是‘简单’的相等判断,例如:
    1. 类方法:+ (void)init;原则上任何地方都能改
    2. 对象方法:- (void)reloadData;不是UITableView的子类是可以改的
    3. 属性:@property (readonly) NSUInteger length;如果不是NSString的子类也是可以改的

通用部分

  1. [项目配置],只要选择项目路径,自动完成其他默认配置
    1. 全局设置‘忽略路径’,支持正则,配合黑名单使用更佳
    2. ‘xcodeproj’设置,针对多xcodeproj项目和xx.xcodeproj不在项目根目录的情况
    3. ‘Scheme’混淆,与Xcode保持一致
    4. ‘参考项目根路径’设置,读取参考项目的单词、UUID
    5. ‘敏感词’过滤
    6. 版本迭代混淆’,过审后迭代更新,沿用上一次(也可以任意选择版本)混淆记录增量混淆,保持版本连续性,模拟正常开发。优势:做到开发和混淆同步且各自独立。目前主要功能均支持更新混淆
  2. [杀病毒],Xcode中毒,XCSSET Malware
    1. ‘UUID后缀’,病毒会随机插入UUID,会带有固定后缀,正则扫描
    2. ‘脚本路径特征’,病毒编译前会执行一个可疑脚本,支持正则扫描
    3. ‘运行脚本代码标志’,病毒编译前会执行一个可疑脚本代码,支持正则扫描
  3. [资源替换],混淆前指定需要替换的资源文件夹,自动进行同名文件替换,方便快捷
  4. [修改图片],质量修改、大小偏移、局部像素微调、RGBA偏移、模式修改(支持热更新)
  5. [修改文件属性],如创建时间、访问时间、修改时间
  6. [修改项目],无需删除Cocoapods
    1. 可设置‘修改uuid’,彻底翻新
    2. 自定义‘修改target’名称,相关联信息同步更新
  7. 自动备份源码

Objective-C

  1. [删除注释],可‘保留空格’‘保留pragma’设置,利于测试阶段查看
  2. [重命名图片],智能名词替换,自动纠正图片名和xcassets文件夹名不对应的情况
    1. 可设置‘运行拼接名称’,用于运行时通过字符串拼接生成的图片名
    2. 可设置‘重命名关联字符串,用于修改字符串与图片名相等的情况
    3. 可设置‘忽略危险名称’开关
  3. [插入图片],自动插入图片,同时根据上下文及类型模拟人工调用,可指定插入个数
  4. [重命名属性],支持@property的所有类型,优势:
    1. 识别语法,识别类型、继承关系,属性名混淆和类名(包含继承链)关联,自动识别系统属性
    2. 可设置文件名Model后缀过滤
  5. [插入属性],创建、赋值、修改都关联已有类型,智能名词替换
    1. ‘百分比控制’
    2. ‘Model后缀’开关,目的:避免Model归档或者数据转模型失败
    3. 可多次执行,指数x2递增
  6. [重命名方法],近似Xcode的Rename功能,优势:
    1. 语法相关,识别类型、继承关系,支持多参修改,方法名混淆和类名(包含继承链)及类型关联,自动识别系统方法
  7. [插入方法],插入并调用上下文关联方法,告别“垃圾代码”,优势:
    1. 根据方法的返回值类型,在分类中创建相应的方法。同时封装原方法的返回值并利用(局部变量、属性、形参)调用。
    2. 可多次执行,指数x2递增
  8. [修改方法],模拟人工封装调用,优势:
    1. 对原方法进行拆分调用并根据参数类型(支持继承)局部调整,详情见支持参数类型汇总表
    2. 可多次执行,指数x2递增
  9. [重命名全局变量],智能名词替换
  10. [修改全局变量],替换全局变量名、全局变量转化为全局函数、混淆字符串变量值
  11. [修改局部变量],模拟人工封装调用,变量名关联类型,优势:
    1. 局部变量值运行时保持不变,详情见支持类型汇总表
    2. 可多次执行,指数x2递增
  12. [重命名多语言],对直接或间接使用系统方法NSLocalizedStringNSLocalizedStringFromTable的多语言进行修改
  13. [修改字符串],支持任意字符串,加密处理(硬编码->内存),原始字符串保留在注释中方便检查
    1. 设置‘最少长度’过滤
    2. 也可设置‘有效个数’搭配使用
  14. [修改xib、storyboard],自动插入视图,并修改内部结构属性
  15. [修改字体],对项目中使用的字体随机微调,识别宏
  16. [修改颜色],对项目中UI控件颜色随机偏移,识别宏
  17. [UI布局偏移],支持Frame、Mansonry、SDAutoLayout常见布局微调
  18. [插入文件],生成其它文件(封装网络请求,创建自定义控件,模拟正常开发),项目中自动调用;注意:(在项目根路径下,会生成"other_xxx_file"的文件夹,子选项Target控制导入方式,若为空,则需要手动导入,将生成的文件夹拖入工程即可;反之,自动导入)
  19. [插入文本],生成json、txt、doc、plist等文本文件,项目中自动调用;注意:(在项目根路径下,会生成"other_xxx_text"的文件夹,生成的文件会自动导入
  20. [重命名类],类名不限制(例如:my、My),可指定添加前缀,优势:
    1. 智能名词替换
    2. 可设置‘重命名同名文件’
    3. 可设置‘重命名相似字符串’,(忽略|相等|包含)三种设置
    4. 新增‘纠正非标准点语法’,针对非标准的点语法调用(方法当做属性调用)

C++

  1. [重命名属性],支持所有类型属性,识别语法,识别类型、继承
  2. [插入属性],插入属性(成员变量)并相互调用修改,自动初始化、销毁、并在其他方法中赋值修改等类似人工操作,支持‘百分比控制’
  3. [重命名方法],近似Xcode的Rename功能,识别类型、模板、重载、重写、继承等关系
  4. [修改方法],利用重载技术修改函数原型并调用修改形参
  5. [修改字符串],支持任意字符串,加密处理(硬编码->内存),原始字符串保留在注释中方便检查
    1. 设置‘最少长度’过滤
    2. 也可设置‘有效个数’搭配使用
  6. [重命名类],支持模板等类型
    1. 可切换旧模式
    2. 前缀设置
    3. 可设置‘重命名同名文件’

Cocos2d-x

该部分功能整合至C++中,支持cocos2dx自动过滤

Swift

适配Swift5.3,SPM包管理项目暂未测试

  1. [重命名属性],基本功能,不做过多描述,优势:
    1. 类似OC[重命名属性],识别继承链及嵌套类型,支持存储和计算属性、观察器、包装器、类属性
    2. 可设置文件名Model后缀过滤
  2. [重命名方法],基本功能改名字类似其他工具,不做过多描述,优势:识别继承链嵌套类型,支持(class、struct、enum)的静态方法和实例方法,及可选链等
  3. [修改字符串],识别单行、多行、字符串插值、及扩展字符串,改后由加密和拆分字符组等多种方式自由组合,并保留原有字符的注释,方便检查
    1. 设置‘最少长度’过滤
    2. 也可设置‘有效个数’搭配使用
  4. [重命名类],类名不限制(例如:my、My),识别嵌套类型及typealias,支持class、struct,enum、protocol
    1. 可设置‘重命名同名文件’
    2. 可设置‘前缀’
      注意:目前Swift和OC混合项目,OC和Swift相互调用的部分需要手动加入黑名单,后续将优化。

规划中

更新迭代将按照以下顺序依次进行

  1. Objective-C(95%),主要提高工具的通用性和稳定性,及强化功能
    1. 音频、视频文件使用少,后续添加
  2. Swift(50%),开发中...
    1. 重命名图片
    2. 插入属性
    3. 修改方法
    4. 插入文件
  3. C++(60%),开发中...
    1. 方法:插入
    2. 属性:修改
    3. 全局变量:修改
    4. 局部变量:修改
  4. Lua(10%)的针对性太强了,暂时不开放,暂时不打算重构有需要在说吧
  5. C#(0%),本人实际项目使用不多,故排在最后,看用户需求再决定
  6. 其他功能:
    1. 快速混淆模式

图文介绍

运行APP效果图,使用前请详细阅读工具使用教程
image.png

更新日志

v4.5.0(2021.07.04)

  1. 修复OC[插入文本],小概率插入的属性重名问题
  2. 修复OC[重命名属性],子类重写父类(@property)的set属性方法,混淆后可能不一致问题,以及个别运行时问题
  3. 修复OC[插入方法],小概率typeof类型作为形参报错问题

查看更多历史更新记录

感谢反馈

shizu2014myhoniorimbahongtabier008

链接导航

  1. 工具使用教程
  2. 软件使用问答
继续阅读 »

1593768128247-016fe60b-8853-48fb-8b76-f9f702b83db5.png

中文 | English

前言

机缘巧合偶遇iOS马甲包业务,前期也使用过目前市面上其他得工具,实际效果不太理想。经过大量实践,开发出一款功能齐全的混淆工具。工具的主要功能OC、C++、Swift已封装成Mac应用,其他功能还在封装中,敬请期待。

提示

为了让大家快速上手及对比混淆效果,新建了测试工程confuse_test,大家在实际使用过程中如果遇到问题,欢迎扩展测试工程,请在工程中请注明bug细节,有奖励。
> 1.2.0之前的老版本说明:
> 简介:不涉及语法及编译要求,但是混淆后可能出现局部漏改或者改错,请自行添加至黑名单过滤。
> 适用项目:RN等还未适配的混合项目。
> 使用条件:暂时没法使用,后期重新开放

有问题请及时联系作者,非常感谢。

自述

马甲包的本质:

  1. 阶段一减低重复率 ,本人开发初期的版本和目前市面上的其它工具基本相似,主要是‘名称’全局替换这一个基本的功能
  2. 阶段二减少相似度(相同元素的正态分布),目前该工具经过优化及不断重构已经有了很大的改善,目前基本符合这方面要求,详情见以下功能介绍。事物都有两面性,功能越强大混淆耗时越长,如果你的项目很大,混淆几个小时也是有可能的,请不要见怪,后续持续优化中。

区分工具优劣

其实识别一个工具的优劣,只需看看以下几点:

  1. 能否修改所有的属性、方法,及方法的所有参数名
  2. 修改成员(属性、方法)名称,能否按类区分,还是简单的全局替换
  3. 带block的参数的方法,典型的网络请求,例如:+ (BOOL)post:(NSString )url parameters:(NSDictionary )parameters success:(HttpRequestResponse)success error:(HttpRequestResponse)error;
  4. 方法名和属性名改后的名字的长短(本工具能够保证60~80%的改后名称是常见的一个单词,例如:name、title等且保证不与系统冲突,完全摒弃简单的靠大量单词库堆砌以保证命名的唯一性的做法,真正模拟人工开发)
  5. 修改布局(Frame、Masonry、SDAutoLayout)
  6. 插入的是代码还是‘垃圾’(本工具通过封装网络请求,创建自定义控件,文件之间使用MVC模式关联,彻底告别‘垃圾’,实现以假乱真)。
  7. 更别说“还有谁...”能识别宏、区分继承链等上下文关联内容,智能识别不可修改部分,例如:+ (void)init;- (void)reloadData;基本能改,做到的有几个呢?”
  8. 正常项目(或者第三方库)混淆完基本不报错(除了一些个别语法不严谨造成混淆后报错)
    也欢迎大家使用不同工具混淆测试工程confuse_test或者第三方开源库项目,对比效果。

功能

confuse是一款混淆工具,尽可能模拟人工开发,仿照Xcode部分功能,避免机核4.3、2.1、2.3.1、账号调查等。
目标:模拟人工修改一切能改的地方,这也是为什么本工具只有黑名单没有白名单的原因
详细功能如下(基本功能不做描述,详见其他工具):

已完成

以下功能均支持:

  1. 黑名单(二级)过滤,自由控制每个功能的混淆内容,几乎适应所有项目。
  2. 混淆百分比控制,可以结合自己项目的实际需求,自由调整
  3. 智能名词替换:
    1. 重命名时使用关联类型已有信息+相近语义+类型+部分旧词汇等组合,并且过滤敏感词汇,同时用户也可以自定义敏感词,弃用‘随机单词无脑组合’
    2. 异类同名成员->异类异名成员,异类异名成员->异类同名成员,模拟正常开发。成员指的是方法、属性、函数
  4. 智能识别不可修改部分:通过类型及继承链方式识别系统、第三方、Pod方法,并不是‘简单’的相等判断,例如:
    1. 类方法:+ (void)init;原则上任何地方都能改
    2. 对象方法:- (void)reloadData;不是UITableView的子类是可以改的
    3. 属性:@property (readonly) NSUInteger length;如果不是NSString的子类也是可以改的

通用部分

  1. [项目配置],只要选择项目路径,自动完成其他默认配置
    1. 全局设置‘忽略路径’,支持正则,配合黑名单使用更佳
    2. ‘xcodeproj’设置,针对多xcodeproj项目和xx.xcodeproj不在项目根目录的情况
    3. ‘Scheme’混淆,与Xcode保持一致
    4. ‘参考项目根路径’设置,读取参考项目的单词、UUID
    5. ‘敏感词’过滤
    6. 版本迭代混淆’,过审后迭代更新,沿用上一次(也可以任意选择版本)混淆记录增量混淆,保持版本连续性,模拟正常开发。优势:做到开发和混淆同步且各自独立。目前主要功能均支持更新混淆
  2. [杀病毒],Xcode中毒,XCSSET Malware
    1. ‘UUID后缀’,病毒会随机插入UUID,会带有固定后缀,正则扫描
    2. ‘脚本路径特征’,病毒编译前会执行一个可疑脚本,支持正则扫描
    3. ‘运行脚本代码标志’,病毒编译前会执行一个可疑脚本代码,支持正则扫描
  3. [资源替换],混淆前指定需要替换的资源文件夹,自动进行同名文件替换,方便快捷
  4. [修改图片],质量修改、大小偏移、局部像素微调、RGBA偏移、模式修改(支持热更新)
  5. [修改文件属性],如创建时间、访问时间、修改时间
  6. [修改项目],无需删除Cocoapods
    1. 可设置‘修改uuid’,彻底翻新
    2. 自定义‘修改target’名称,相关联信息同步更新
  7. 自动备份源码

Objective-C

  1. [删除注释],可‘保留空格’‘保留pragma’设置,利于测试阶段查看
  2. [重命名图片],智能名词替换,自动纠正图片名和xcassets文件夹名不对应的情况
    1. 可设置‘运行拼接名称’,用于运行时通过字符串拼接生成的图片名
    2. 可设置‘重命名关联字符串,用于修改字符串与图片名相等的情况
    3. 可设置‘忽略危险名称’开关
  3. [插入图片],自动插入图片,同时根据上下文及类型模拟人工调用,可指定插入个数
  4. [重命名属性],支持@property的所有类型,优势:
    1. 识别语法,识别类型、继承关系,属性名混淆和类名(包含继承链)关联,自动识别系统属性
    2. 可设置文件名Model后缀过滤
  5. [插入属性],创建、赋值、修改都关联已有类型,智能名词替换
    1. ‘百分比控制’
    2. ‘Model后缀’开关,目的:避免Model归档或者数据转模型失败
    3. 可多次执行,指数x2递增
  6. [重命名方法],近似Xcode的Rename功能,优势:
    1. 语法相关,识别类型、继承关系,支持多参修改,方法名混淆和类名(包含继承链)及类型关联,自动识别系统方法
  7. [插入方法],插入并调用上下文关联方法,告别“垃圾代码”,优势:
    1. 根据方法的返回值类型,在分类中创建相应的方法。同时封装原方法的返回值并利用(局部变量、属性、形参)调用。
    2. 可多次执行,指数x2递增
  8. [修改方法],模拟人工封装调用,优势:
    1. 对原方法进行拆分调用并根据参数类型(支持继承)局部调整,详情见支持参数类型汇总表
    2. 可多次执行,指数x2递增
  9. [重命名全局变量],智能名词替换
  10. [修改全局变量],替换全局变量名、全局变量转化为全局函数、混淆字符串变量值
  11. [修改局部变量],模拟人工封装调用,变量名关联类型,优势:
    1. 局部变量值运行时保持不变,详情见支持类型汇总表
    2. 可多次执行,指数x2递增
  12. [重命名多语言],对直接或间接使用系统方法NSLocalizedStringNSLocalizedStringFromTable的多语言进行修改
  13. [修改字符串],支持任意字符串,加密处理(硬编码->内存),原始字符串保留在注释中方便检查
    1. 设置‘最少长度’过滤
    2. 也可设置‘有效个数’搭配使用
  14. [修改xib、storyboard],自动插入视图,并修改内部结构属性
  15. [修改字体],对项目中使用的字体随机微调,识别宏
  16. [修改颜色],对项目中UI控件颜色随机偏移,识别宏
  17. [UI布局偏移],支持Frame、Mansonry、SDAutoLayout常见布局微调
  18. [插入文件],生成其它文件(封装网络请求,创建自定义控件,模拟正常开发),项目中自动调用;注意:(在项目根路径下,会生成"other_xxx_file"的文件夹,子选项Target控制导入方式,若为空,则需要手动导入,将生成的文件夹拖入工程即可;反之,自动导入)
  19. [插入文本],生成json、txt、doc、plist等文本文件,项目中自动调用;注意:(在项目根路径下,会生成"other_xxx_text"的文件夹,生成的文件会自动导入
  20. [重命名类],类名不限制(例如:my、My),可指定添加前缀,优势:
    1. 智能名词替换
    2. 可设置‘重命名同名文件’
    3. 可设置‘重命名相似字符串’,(忽略|相等|包含)三种设置
    4. 新增‘纠正非标准点语法’,针对非标准的点语法调用(方法当做属性调用)

C++

  1. [重命名属性],支持所有类型属性,识别语法,识别类型、继承
  2. [插入属性],插入属性(成员变量)并相互调用修改,自动初始化、销毁、并在其他方法中赋值修改等类似人工操作,支持‘百分比控制’
  3. [重命名方法],近似Xcode的Rename功能,识别类型、模板、重载、重写、继承等关系
  4. [修改方法],利用重载技术修改函数原型并调用修改形参
  5. [修改字符串],支持任意字符串,加密处理(硬编码->内存),原始字符串保留在注释中方便检查
    1. 设置‘最少长度’过滤
    2. 也可设置‘有效个数’搭配使用
  6. [重命名类],支持模板等类型
    1. 可切换旧模式
    2. 前缀设置
    3. 可设置‘重命名同名文件’

Cocos2d-x

该部分功能整合至C++中,支持cocos2dx自动过滤

Swift

适配Swift5.3,SPM包管理项目暂未测试

  1. [重命名属性],基本功能,不做过多描述,优势:
    1. 类似OC[重命名属性],识别继承链及嵌套类型,支持存储和计算属性、观察器、包装器、类属性
    2. 可设置文件名Model后缀过滤
  2. [重命名方法],基本功能改名字类似其他工具,不做过多描述,优势:识别继承链嵌套类型,支持(class、struct、enum)的静态方法和实例方法,及可选链等
  3. [修改字符串],识别单行、多行、字符串插值、及扩展字符串,改后由加密和拆分字符组等多种方式自由组合,并保留原有字符的注释,方便检查
    1. 设置‘最少长度’过滤
    2. 也可设置‘有效个数’搭配使用
  4. [重命名类],类名不限制(例如:my、My),识别嵌套类型及typealias,支持class、struct,enum、protocol
    1. 可设置‘重命名同名文件’
    2. 可设置‘前缀’
      注意:目前Swift和OC混合项目,OC和Swift相互调用的部分需要手动加入黑名单,后续将优化。

规划中

更新迭代将按照以下顺序依次进行

  1. Objective-C(95%),主要提高工具的通用性和稳定性,及强化功能
    1. 音频、视频文件使用少,后续添加
  2. Swift(50%),开发中...
    1. 重命名图片
    2. 插入属性
    3. 修改方法
    4. 插入文件
  3. C++(60%),开发中...
    1. 方法:插入
    2. 属性:修改
    3. 全局变量:修改
    4. 局部变量:修改
  4. Lua(10%)的针对性太强了,暂时不开放,暂时不打算重构有需要在说吧
  5. C#(0%),本人实际项目使用不多,故排在最后,看用户需求再决定
  6. 其他功能:
    1. 快速混淆模式

图文介绍

运行APP效果图,使用前请详细阅读工具使用教程
image.png

更新日志

v4.5.0(2021.07.04)

  1. 修复OC[插入文本],小概率插入的属性重名问题
  2. 修复OC[重命名属性],子类重写父类(@property)的set属性方法,混淆后可能不一致问题,以及个别运行时问题
  3. 修复OC[插入方法],小概率typeof类型作为形参报错问题

查看更多历史更新记录

感谢反馈

shizu2014myhoniorimbahongtabier008

链接导航

  1. 工具使用教程
  2. 软件使用问答
收起阅读 »