HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

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. 软件使用问答
收起阅读 »

建议dcloud再去接入阿里云,腾讯云测试的资源

云服务

一些不报错的bug,比如css样式上的bug,没有真机测试是不行的,偏偏现在差异化的各大平台,测试起来真心费劲

建议dcloud再去接入阿里云,腾讯云测试的资源,能够每个平台能用测试用例自动根据测试用例操作,自动截图的那种

一些不报错的bug,比如css样式上的bug,没有真机测试是不行的,偏偏现在差异化的各大平台,测试起来真心费劲

建议dcloud再去接入阿里云,腾讯云测试的资源,能够每个平台能用测试用例自动根据测试用例操作,自动截图的那种

uniapp app端打开微信小程序轮子

            // #ifdef APP-PLUS  
            contact() {  
                //需调用plus.share.getServices获取微信分享服务对象  
                plus.share.getServices((s) => {  
                    let sweixin = {};  
                    for (let i = 0; i < s.length; i++) {  
                        let share = s[i];  
                        if (share.id === 'weixin') {  
                            sweixin = share  
                        }  
                    }  
                    //小程序参数,必填  
                    let WeixinMiniProgramOptions = {  
                        id: 'gh_33446d7f7a26',  
                        path:'/pages/me/index' //可指定打开的页面  
                    }  
                    sweixin ? sweixin.launchMiniProgram(WeixinMiniProgramOptions) : plus.nativeUI.alert(  
                        '当前环境不支持微信操作!');  
                }, function(e) {  
                    console.log("获取分享服务列表失败:" + e.message);  
                });  
            },  
            // #endif
继续阅读 »
            // #ifdef APP-PLUS  
            contact() {  
                //需调用plus.share.getServices获取微信分享服务对象  
                plus.share.getServices((s) => {  
                    let sweixin = {};  
                    for (let i = 0; i < s.length; i++) {  
                        let share = s[i];  
                        if (share.id === 'weixin') {  
                            sweixin = share  
                        }  
                    }  
                    //小程序参数,必填  
                    let WeixinMiniProgramOptions = {  
                        id: 'gh_33446d7f7a26',  
                        path:'/pages/me/index' //可指定打开的页面  
                    }  
                    sweixin ? sweixin.launchMiniProgram(WeixinMiniProgramOptions) : plus.nativeUI.alert(  
                        '当前环境不支持微信操作!');  
                }, function(e) {  
                    console.log("获取分享服务列表失败:" + e.message);  
                });  
            },  
            // #endif
收起阅读 »

OPPO上架成功,质量为A级!

应用上架

OPPO上架成功,质量为A级!
不知道大家上架OPPO的质量是B还是A ?不知道这个A有多大作用?

PS:感谢uniapp!

OPPO上架成功,质量为A级!
不知道大家上架OPPO的质量是B还是A ?不知道这个A有多大作用?

PS:感谢uniapp!

uni-app 自定义隐私弹窗样式

隐私弹窗

1 前置条件

  1. hx 3.1.23之后版本

  2. 仅支持uni-app

  3. 仅Android

2 功能说明

HX 3.1.23之前,uni-app默认支持了隐私协议弹窗功能,开发者只要根据文档在manifest.json中配置对应的文案,即可使用固定模板的隐私弹窗

相关的操作文档:https://ask.dcloud.net.cn/article/36937

HX 3.1.23之后,应开发者的需求。uni-app 支持自定义隐私弹窗样式。

隐私弹窗的一级布局文件为
dcloud_custom_privacy_dialog_layout.xml
对应的界面:

隐私弹窗的二级布局文件为
dcloud_custom_privacy_second_dialog_layout.xml
对应的界面:

有需要自定义样式的开发者,只要保证关键组件id不变,界面布局可以自由更改。
下面是一个具备基础元素的布局示例。

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/ll_content_layout"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:background="@drawable/dcloud_dialog_shape"  
    android:gravity="center"  
    android:orientation="vertical">  

    <!--隐私协议标题-->  
    <TextView  
        android:id="@+id/tv_custom_privacy_title"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_marginBottom="12dp"  
        android:gravity="center"  
        android:paddingTop="20dp"  
        android:textColor="#000000"  
        android:textSize="16sp"  
        android:textStyle="bold" />  
    <!--隐私协议内容-->  
    <TextView  
        android:id="@+id/tv_privacy_content"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:paddingLeft="12dp"  
        android:paddingTop="6dp"  
        android:paddingRight="12dp"  
        android:paddingBottom="2dp"  
         <!--这里可以控制协议内容中的超链接样式,包括链接颜色以及是否有下划线-->  
        android:tag="{'linkColor':'#FF00FF','linkLine':false}" />  

    <!--用户按钮-->  
    <LinearLayout  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:paddingLeft="12dp"  
        android:paddingTop="2dp"  
        android:paddingRight="12dp"  
        android:paddingBottom="8dp">  

        <Button  
            android:id="@+id/btn_custom_privacy_cancel"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_weight="1"  
            android:background="@null"  
            android:paddingLeft="12dp"  
            android:paddingTop="10dp"  
            android:paddingRight="12dp"  
            android:paddingBottom="10dp"  
            android:text="取消"  
            android:textColor="@drawable/dcloud_custom_rich_dialog_button_text_selecter"  
            android:textSize="14sp"  
            android:visibility="gone" />  

        <Button  
            android:id="@+id/btn_custom_privacy_sure"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_weight="1"  
            android:background="@null"  
            android:paddingLeft="12dp"  
            android:paddingTop="10dp"  
            android:paddingRight="12dp"  
            android:paddingBottom="10dp"  
            android:text="确认"  
            android:textColor="@drawable/dcloud_custom_rich_dialog_button_text_selecter"  
            android:textSize="14sp"  
            android:visibility="gone" />  

    </LinearLayout>  
</LinearLayout>

明确一个基本原则,隐私弹窗的布局文件 完全按照android 布局文件格式标准。
具备Android原生开发能力的人,可以在不修改基本元素组件id的前提下,自由发挥。

将修改后的同名布局文件,以原生插件的方式提交打包,即可完成对隐私弹窗的覆盖。

3 演示操作步骤

第一步配置默认隐私协议文案:

此时的运行效果

第二步 新建一个原生插件

说明文档:https://nativesupport.dcloud.net.cn/NativePlugin/README

在对应的android/res/layout 目录下,添加一二级布局文件
目录结构如下:

第三步 修改隐私协议弹窗样式

这里只简单修改一下超链接样式。如果需要修改其他内容,需要自行查询android xml布局

将修改后的xml布局保存,打包成原生插件

第四步,集成原生插件,云打包验证效果。

提交云端打包后的运行效果:

演示插件

演示插件:
https://ext.dcloud.net.cn/plugin?id=5581

演示项目

https://download.dcloud.net.cn/ASK_RESOURCE/PrivacyDemo.zip

继续阅读 »

1 前置条件

  1. hx 3.1.23之后版本

  2. 仅支持uni-app

  3. 仅Android

2 功能说明

HX 3.1.23之前,uni-app默认支持了隐私协议弹窗功能,开发者只要根据文档在manifest.json中配置对应的文案,即可使用固定模板的隐私弹窗

相关的操作文档:https://ask.dcloud.net.cn/article/36937

HX 3.1.23之后,应开发者的需求。uni-app 支持自定义隐私弹窗样式。

隐私弹窗的一级布局文件为
dcloud_custom_privacy_dialog_layout.xml
对应的界面:

隐私弹窗的二级布局文件为
dcloud_custom_privacy_second_dialog_layout.xml
对应的界面:

有需要自定义样式的开发者,只要保证关键组件id不变,界面布局可以自由更改。
下面是一个具备基础元素的布局示例。

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/ll_content_layout"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:background="@drawable/dcloud_dialog_shape"  
    android:gravity="center"  
    android:orientation="vertical">  

    <!--隐私协议标题-->  
    <TextView  
        android:id="@+id/tv_custom_privacy_title"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_marginBottom="12dp"  
        android:gravity="center"  
        android:paddingTop="20dp"  
        android:textColor="#000000"  
        android:textSize="16sp"  
        android:textStyle="bold" />  
    <!--隐私协议内容-->  
    <TextView  
        android:id="@+id/tv_privacy_content"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:paddingLeft="12dp"  
        android:paddingTop="6dp"  
        android:paddingRight="12dp"  
        android:paddingBottom="2dp"  
         <!--这里可以控制协议内容中的超链接样式,包括链接颜色以及是否有下划线-->  
        android:tag="{'linkColor':'#FF00FF','linkLine':false}" />  

    <!--用户按钮-->  
    <LinearLayout  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:paddingLeft="12dp"  
        android:paddingTop="2dp"  
        android:paddingRight="12dp"  
        android:paddingBottom="8dp">  

        <Button  
            android:id="@+id/btn_custom_privacy_cancel"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_weight="1"  
            android:background="@null"  
            android:paddingLeft="12dp"  
            android:paddingTop="10dp"  
            android:paddingRight="12dp"  
            android:paddingBottom="10dp"  
            android:text="取消"  
            android:textColor="@drawable/dcloud_custom_rich_dialog_button_text_selecter"  
            android:textSize="14sp"  
            android:visibility="gone" />  

        <Button  
            android:id="@+id/btn_custom_privacy_sure"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_weight="1"  
            android:background="@null"  
            android:paddingLeft="12dp"  
            android:paddingTop="10dp"  
            android:paddingRight="12dp"  
            android:paddingBottom="10dp"  
            android:text="确认"  
            android:textColor="@drawable/dcloud_custom_rich_dialog_button_text_selecter"  
            android:textSize="14sp"  
            android:visibility="gone" />  

    </LinearLayout>  
</LinearLayout>

明确一个基本原则,隐私弹窗的布局文件 完全按照android 布局文件格式标准。
具备Android原生开发能力的人,可以在不修改基本元素组件id的前提下,自由发挥。

将修改后的同名布局文件,以原生插件的方式提交打包,即可完成对隐私弹窗的覆盖。

3 演示操作步骤

第一步配置默认隐私协议文案:

此时的运行效果

第二步 新建一个原生插件

说明文档:https://nativesupport.dcloud.net.cn/NativePlugin/README

在对应的android/res/layout 目录下,添加一二级布局文件
目录结构如下:

第三步 修改隐私协议弹窗样式

这里只简单修改一下超链接样式。如果需要修改其他内容,需要自行查询android xml布局

将修改后的xml布局保存,打包成原生插件

第四步,集成原生插件,云打包验证效果。

提交云端打包后的运行效果:

演示插件

演示插件:
https://ext.dcloud.net.cn/plugin?id=5581

演示项目

https://download.dcloud.net.cn/ASK_RESOURCE/PrivacyDemo.zip

收起阅读 »

关于应用校验及常见问题的说明

应用详情地址 获取应用下载地址 获取应用下载链接 关于应用校验及常见问题的说明 应用商店 获取应用商店地址

什么是APK下载链接、详情页链接?

  • APK链接:点击后可以直接唤起APK应用包下载的链接,即为APK链接。例如:https://imtt.dd.qq.com/16891/DBB2D18C1A390C6AC9DB067C94F57F3E.apk?fsname=com.yunbu.magicgarden.tencent_1.1.13_10113.apk&csr=1bbd
  • 详情页链接:即应用商店的下载详情页,例如:http://info.appstore.vivo.com.cn/detail/2853962

安卓应用校验方式

  • 1.自动校验:当您填写所选应用商店的apk下载链接时,则自动进行校验。您所填写的链接必须包含该应用商店域名。获取方式参考以下几种:
  • 方法一:您可以在应用商店将此应用下载,并在“下载内容”中复制该链接地址,适合使用此方法的商店包括:应用宝、小米/小米游戏、vivo游戏/vivo、应用汇、9游、安智、乐商店、2345、爱奇艺游戏、TikTok。

  • 方法二:OPPO商店获取apk下载链接步骤
  • 第一步:https://app.cdo.oppomobile.com/home/detail?app_id=(此处拼接OPPO分配的审核成功的Appid);
  • 第二步:通过浏览器打开第一步拼接好的详情页链接进行下载,并在“下载内容”中复制该链接地址。
    注:个别应用可能无法通过此方法获取下载地址,若出现无法获取的情况建议使用其他商店下载地址进行应用创建

  • 方法三:查看应用商店的开发者管理后台,如提供APK下载链接地址,复制并填写即可。目前确认可提供此链接的商店包括:4399、豌豆荚、搜狗、美图;

  • 方法四:如果您选择的应用商店,会跳转到UC、PP助手等其他商店,请按照域名选择相应渠道。我们会对一个应用进行双重校验。

    • 第一,校验应用的真实性,您需要填写应用的包名、链接;
    • 第二,校验应用的唯一性,您需要填写完整的正确包名;
    • 第三,校验应用所有权的真实性,您需要填写SHA1值。
  • 方法五:针对 360 应用市场

    • 360 应用市场需提供 WAP 端的详情页链接。
    • 您可在 PC 浏览器中打开开发者工具,点击第二个图标进行 PC 和 WAP 的切换,在浏览器里再次输入360的推广链接,如http://zhushou.360.cn/detail/index/soft_id/46xxxxxx,回车后,即可得到由 m.app.so.com 开头的 WAP 端详情页链接,如:http://m.app.so.com/detail/index?pname=com.baidu.searchbox&id=5846

  • 方法六:针对应用宝市场的部分应用
    • 问题:部分应用在应用宝市场无下载入口
    • 解决方法:下载应用宝电脑版应用,在应用内搜索您的 APP,选择页面右上方的 icon,点击下载apk,会自动调起应用宝详情页

  • 点击下载 APP

  • 完成后在下载记录里查询下载地址

创建失败的常见原因

1.应用下载出错:除了苹果商店、好游快爆、TapTap、华为商店、360和魅族,您都需要填写APK下载链接,如果您填写了详情页链接,则无法创建成功;另外,如果此APK链接无法顺利下载,也会出现“下载出错”的提示
2.解析超时:由于网络问题或包体太大(大于250M),会出现下载超时,这种情况下,该应用将被转为人工审核
3.SHA1、包名填写错误:请检查所填写内容是否是该应用真实正确的SHA1、包名
5.包名重复:说明此应用在穿山甲已有应用ID,请及时联系联系邮箱: uniad@dcloud.io
6.包名解析出错: 穿山甲无法根据您提供的商店链接找到应用,常见于itunes链接。主要原因为您的APP只在特定国家/地区上架,需要在链接中加入国家/地区代码,才能获取应用。例:抖音中国版(https://apps.apple.com/cn/app/id1142110895) 如果去掉链接中的cn(https://apps.apple.com/app/id1142110895)则无法从商店获取相关信息。

继续阅读 »

什么是APK下载链接、详情页链接?

  • APK链接:点击后可以直接唤起APK应用包下载的链接,即为APK链接。例如:https://imtt.dd.qq.com/16891/DBB2D18C1A390C6AC9DB067C94F57F3E.apk?fsname=com.yunbu.magicgarden.tencent_1.1.13_10113.apk&csr=1bbd
  • 详情页链接:即应用商店的下载详情页,例如:http://info.appstore.vivo.com.cn/detail/2853962

安卓应用校验方式

  • 1.自动校验:当您填写所选应用商店的apk下载链接时,则自动进行校验。您所填写的链接必须包含该应用商店域名。获取方式参考以下几种:
  • 方法一:您可以在应用商店将此应用下载,并在“下载内容”中复制该链接地址,适合使用此方法的商店包括:应用宝、小米/小米游戏、vivo游戏/vivo、应用汇、9游、安智、乐商店、2345、爱奇艺游戏、TikTok。

  • 方法二:OPPO商店获取apk下载链接步骤
  • 第一步:https://app.cdo.oppomobile.com/home/detail?app_id=(此处拼接OPPO分配的审核成功的Appid);
  • 第二步:通过浏览器打开第一步拼接好的详情页链接进行下载,并在“下载内容”中复制该链接地址。
    注:个别应用可能无法通过此方法获取下载地址,若出现无法获取的情况建议使用其他商店下载地址进行应用创建

  • 方法三:查看应用商店的开发者管理后台,如提供APK下载链接地址,复制并填写即可。目前确认可提供此链接的商店包括:4399、豌豆荚、搜狗、美图;

  • 方法四:如果您选择的应用商店,会跳转到UC、PP助手等其他商店,请按照域名选择相应渠道。我们会对一个应用进行双重校验。

    • 第一,校验应用的真实性,您需要填写应用的包名、链接;
    • 第二,校验应用的唯一性,您需要填写完整的正确包名;
    • 第三,校验应用所有权的真实性,您需要填写SHA1值。
  • 方法五:针对 360 应用市场

    • 360 应用市场需提供 WAP 端的详情页链接。
    • 您可在 PC 浏览器中打开开发者工具,点击第二个图标进行 PC 和 WAP 的切换,在浏览器里再次输入360的推广链接,如http://zhushou.360.cn/detail/index/soft_id/46xxxxxx,回车后,即可得到由 m.app.so.com 开头的 WAP 端详情页链接,如:http://m.app.so.com/detail/index?pname=com.baidu.searchbox&id=5846

  • 方法六:针对应用宝市场的部分应用
    • 问题:部分应用在应用宝市场无下载入口
    • 解决方法:下载应用宝电脑版应用,在应用内搜索您的 APP,选择页面右上方的 icon,点击下载apk,会自动调起应用宝详情页

  • 点击下载 APP

  • 完成后在下载记录里查询下载地址

创建失败的常见原因

1.应用下载出错:除了苹果商店、好游快爆、TapTap、华为商店、360和魅族,您都需要填写APK下载链接,如果您填写了详情页链接,则无法创建成功;另外,如果此APK链接无法顺利下载,也会出现“下载出错”的提示
2.解析超时:由于网络问题或包体太大(大于250M),会出现下载超时,这种情况下,该应用将被转为人工审核
3.SHA1、包名填写错误:请检查所填写内容是否是该应用真实正确的SHA1、包名
5.包名重复:说明此应用在穿山甲已有应用ID,请及时联系联系邮箱: uniad@dcloud.io
6.包名解析出错: 穿山甲无法根据您提供的商店链接找到应用,常见于itunes链接。主要原因为您的APP只在特定国家/地区上架,需要在链接中加入国家/地区代码,才能获取应用。例:抖音中国版(https://apps.apple.com/cn/app/id1142110895) 如果去掉链接中的cn(https://apps.apple.com/app/id1142110895)则无法从商店获取相关信息。

收起阅读 »

盲盒系统运营优势特色功能

小程序

每个行业的行业属性不同,其具体的销售策略和推广方式也有所不同,模板小程序只能在模板规定的范围内换图片、填充内容,在功能和玩法上无法满足各行各业不同商家之间的个性化需求。同时,盲盒抽盒小程序作为一种新颖的小程序类型,在当前的小程序模板市场并不成熟,也很少见。
而找专业公司定制开发的微信盲盒小程序则可以完全依据自己的营销方案和发展策略定制各种个性化功能玩法。定制开发的微信盲盒抽盒小程序就可以顺应品牌方的要求,开发PLUS会员、积分打榜、NFC防伪交互等多种新颖的功能玩法,增强盲盒抽盒平台的趣味性和竞争力,为消费者带来新奇有趣的消费体验。

继续阅读 »

每个行业的行业属性不同,其具体的销售策略和推广方式也有所不同,模板小程序只能在模板规定的范围内换图片、填充内容,在功能和玩法上无法满足各行各业不同商家之间的个性化需求。同时,盲盒抽盒小程序作为一种新颖的小程序类型,在当前的小程序模板市场并不成熟,也很少见。
而找专业公司定制开发的微信盲盒小程序则可以完全依据自己的营销方案和发展策略定制各种个性化功能玩法。定制开发的微信盲盒抽盒小程序就可以顺应品牌方的要求,开发PLUS会员、积分打榜、NFC防伪交互等多种新颖的功能玩法,增强盲盒抽盒平台的趣味性和竞争力,为消费者带来新奇有趣的消费体验。

收起阅读 »

404

原生分享

404

404

福玩商城盲盒app软件开发

小程序

1、线下自提
  app开发还有线下自提的功能。用户可以利用手机导航定位找到附近的盲盒智能售货机,然后扫码兑换盲盒。
  2、产品回收
  由于盲盒消费会产生大量的复购行为,有些用户会多次获得同一款产品,影响消费体验,因此平台支持在线拆盲盒后的产品回收功能,用户拆到重复或不满意产品平台可以折价回收,返还相应的购物积分用于下次的购买,提升用户储值几率和购物粘性。
  3、盲盒商城
  盲盒app开发的功能有盲盒商城。在手机app上,可以设置好特殊产品和常规产品,用户任意选择一个或多个盲盒购买,在线拆盲盒后可即可得知产品内容,并且将线下寄送盲盒到家。
  4、盲盒社区
  盲盒app开发还有盲盒社区的功能。在盲盒社区版块,用户可以通过图片、文字或视频等方式分享自己的盲盒款式和其它盲盒爱好者进行交流。
  5、抽奖功能
  盲盒app开发可以进行抽奖,用户可以在app上做系统任务,也可以分享,从而得到积分,当积分积累到一定值的时候,用户就可以在线上进行抽奖,从而获得隐藏款盲盒套装,激发用户的消费热情。
  6、好友邀请
  在app上,用户可以使用邀请码邀请好友成功消费盲盒后,双方都将获得一定奖励,例如代金券、购物积分等,可用于盲盒商城上的消费。

继续阅读 »

1、线下自提
  app开发还有线下自提的功能。用户可以利用手机导航定位找到附近的盲盒智能售货机,然后扫码兑换盲盒。
  2、产品回收
  由于盲盒消费会产生大量的复购行为,有些用户会多次获得同一款产品,影响消费体验,因此平台支持在线拆盲盒后的产品回收功能,用户拆到重复或不满意产品平台可以折价回收,返还相应的购物积分用于下次的购买,提升用户储值几率和购物粘性。
  3、盲盒商城
  盲盒app开发的功能有盲盒商城。在手机app上,可以设置好特殊产品和常规产品,用户任意选择一个或多个盲盒购买,在线拆盲盒后可即可得知产品内容,并且将线下寄送盲盒到家。
  4、盲盒社区
  盲盒app开发还有盲盒社区的功能。在盲盒社区版块,用户可以通过图片、文字或视频等方式分享自己的盲盒款式和其它盲盒爱好者进行交流。
  5、抽奖功能
  盲盒app开发可以进行抽奖,用户可以在app上做系统任务,也可以分享,从而得到积分,当积分积累到一定值的时候,用户就可以在线上进行抽奖,从而获得隐藏款盲盒套装,激发用户的消费热情。
  6、好友邀请
  在app上,用户可以使用邀请码邀请好友成功消费盲盒后,双方都将获得一定奖励,例如代金券、购物积分等,可用于盲盒商城上的消费。

收起阅读 »

小程序商城的优势

小程序

1.完美实现快捷方便的购物。微信作为常用的社交软件,可以随时随地在微商城里快捷的打开入口,方便用户购买。用户只需利用空余时间,就可以自主的查看产品信息并快速下单。并且由于微商城是建立在成熟社交平台上的销售系统,引流十分迅速,商家可以在短时间内拥有大量的客户群。

  1. 成本低廉对于创业者和传统商家来说,小程序可以大大降低运营成本,从开发成本到运营期的花费,小程序的花费仅占开发专门的APP的成本的10%左右。
    3.有利于打造品牌效应商家建立商城小程序后可以实现分享功能,小程序页面内有一键分享功能,可以轻松的实现转发到多个平台,实现扩大更多曝光范围。那么如此做法会提升客户对该平台的认知度,提升客户对该品牌的信任度,这对企业打造品牌有更好的帮助。
继续阅读 »

1.完美实现快捷方便的购物。微信作为常用的社交软件,可以随时随地在微商城里快捷的打开入口,方便用户购买。用户只需利用空余时间,就可以自主的查看产品信息并快速下单。并且由于微商城是建立在成熟社交平台上的销售系统,引流十分迅速,商家可以在短时间内拥有大量的客户群。

  1. 成本低廉对于创业者和传统商家来说,小程序可以大大降低运营成本,从开发成本到运营期的花费,小程序的花费仅占开发专门的APP的成本的10%左右。
    3.有利于打造品牌效应商家建立商城小程序后可以实现分享功能,小程序页面内有一键分享功能,可以轻松的实现转发到多个平台,实现扩大更多曝光范围。那么如此做法会提升客户对该平台的认知度,提升客户对该品牌的信任度,这对企业打造品牌有更好的帮助。
收起阅读 »

哪些行业适合开发小程序使用?

小程序

说到小程序不得不说一下微信,微信可以说是国内日活最高的APP,日活近10亿,接近国内APP日活的天花板。小程序背靠微信日活也实现4亿+。随着移动互联网的飞速发展,小程序覆盖的细分行业超两百多个,十万名程序员投入到小程序的开发中来,那么有哪些行业适合开发小程序使用呢?

1、预定类

预定类小程序现在受到越来越多的人喜欢,也被越来越多的人使用,其中一方面是因为预定类小程序可以直接线上支付,省去了一些挂号、排队的时间,另一方面小程序上面的导航、定位功能也越来越成熟。并且小程序打开即用不占内存,使得用户体验效果极佳。因此越来越多酒店、美容、医护、KTV等行业选择做小程序。

2、新零售类

新零售的核心就是线上服务、线下体验以及对现代物流进行深度融合的方式,这样使得用户形成叠加交叉的形式,作为连接线下的工具,效果是空前的好,这将是商家实现销售的更好方式。

3、生活服务类

生活服务是一个范围很广的圈子,其中包括很多行业,主要以衣、食、住、行为主,这些都是我们平时可以用得到的,包括餐饮、住宿、出行,都是我们平时使用比较频繁的,这些小程序都可以实现用户自主下单,备注口味,并且需要多少钱都是提前知道的,并且商家也节约了部分人工成本,也可以提升商家线上业绩,让商家利用线上平台进项获客、锁客以及更加有效地推广。

4、电商类

小程序可以说是电商的补充产品,其中有微信支付、订单填写、商品上下架功能,能够让用户减少决策时间,更快地达成购买,并且交易和购买不需要跳转APP,可以说是相当方便。而且虽然是主打轻量级服务的小程序,但微信客服功能依然存在,用户想提问就可以进行提问。

5、知识付费类

现在很多知识付费平台开始开发小程序来锁客,用户可以在小程序上面指定讲师为自己讲解自己需要的内容,商家可以让讲师入驻其中,还可以加入推广功能,让更多让帮助推荐以获取更大的收益。小程序还可以对之前讲师讲过的重点内容进行暂停、回放,以达到重复学习多次记忆的效果。

可以说,只要你拥有大的用户量以及你想拥有大的用户量都可以使用小程序,或者提供特定的功能类小程序。小程序的功能多是展示或引流为主,不管是哪个行业基本都会用到小程序,只是用法上不同。当然,小程序只是营销生态链的一个工具,如果有其他营销推广的配合,在获取客户信任度的基础上,效果可以达到事半功倍的效果。

继续阅读 »

说到小程序不得不说一下微信,微信可以说是国内日活最高的APP,日活近10亿,接近国内APP日活的天花板。小程序背靠微信日活也实现4亿+。随着移动互联网的飞速发展,小程序覆盖的细分行业超两百多个,十万名程序员投入到小程序的开发中来,那么有哪些行业适合开发小程序使用呢?

1、预定类

预定类小程序现在受到越来越多的人喜欢,也被越来越多的人使用,其中一方面是因为预定类小程序可以直接线上支付,省去了一些挂号、排队的时间,另一方面小程序上面的导航、定位功能也越来越成熟。并且小程序打开即用不占内存,使得用户体验效果极佳。因此越来越多酒店、美容、医护、KTV等行业选择做小程序。

2、新零售类

新零售的核心就是线上服务、线下体验以及对现代物流进行深度融合的方式,这样使得用户形成叠加交叉的形式,作为连接线下的工具,效果是空前的好,这将是商家实现销售的更好方式。

3、生活服务类

生活服务是一个范围很广的圈子,其中包括很多行业,主要以衣、食、住、行为主,这些都是我们平时可以用得到的,包括餐饮、住宿、出行,都是我们平时使用比较频繁的,这些小程序都可以实现用户自主下单,备注口味,并且需要多少钱都是提前知道的,并且商家也节约了部分人工成本,也可以提升商家线上业绩,让商家利用线上平台进项获客、锁客以及更加有效地推广。

4、电商类

小程序可以说是电商的补充产品,其中有微信支付、订单填写、商品上下架功能,能够让用户减少决策时间,更快地达成购买,并且交易和购买不需要跳转APP,可以说是相当方便。而且虽然是主打轻量级服务的小程序,但微信客服功能依然存在,用户想提问就可以进行提问。

5、知识付费类

现在很多知识付费平台开始开发小程序来锁客,用户可以在小程序上面指定讲师为自己讲解自己需要的内容,商家可以让讲师入驻其中,还可以加入推广功能,让更多让帮助推荐以获取更大的收益。小程序还可以对之前讲师讲过的重点内容进行暂停、回放,以达到重复学习多次记忆的效果。

可以说,只要你拥有大的用户量以及你想拥有大的用户量都可以使用小程序,或者提供特定的功能类小程序。小程序的功能多是展示或引流为主,不管是哪个行业基本都会用到小程序,只是用法上不同。当然,小程序只是营销生态链的一个工具,如果有其他营销推广的配合,在获取客户信任度的基础上,效果可以达到事半功倍的效果。

收起阅读 »