手游SDK-混淆

一、SDK与APP混淆的区别

SDK混淆和APP相比除了常用的混淆配置以外,还需要避免混淆暴露给游戏的接口。同时为了避免游戏接入SDK之后混淆了关键代码导致闪退,SDK还需要提供一份混淆配置文件。

二、混淆基础

Android的代码混淆只需要在AS的build.gradle中配置开启即可。
示例代码如下:


    buildTypes {
        release {
            minifyEnabled true     // true - 打开混淆
            shrinkResources false  // true - 打开资源压缩
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro',
                    '../libModule/proguard-rules.pro'  // 用于设置Proguard的规划路径;
        }
    }
    

minifyEnabled 为是否打开混淆

shrinkResources 为是否打开资源压缩。即删除APK中多余的资源。
但如果不是对包体大小很敏感,不建议开启shrinkResources,很容易踩坑。因为如果开启了只有在程序中使用了R.xx.xx的资源才不会被删除。而没有被引用或者通过文件名搜索等方法引用的资源,将会被优化掉。
如果一定要使用,注意要把没有被R.xx.xx引用的资源添加到 res–raw—keep.xml。
keep.xml的示例代码:


<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@drawable/photo1,@drawable/photo2"
    

proguard-android.txt 是系统默认的混淆文件,具体在…/sdk/tools/proguard/ 目录下,其中包含了 android 最基本的混淆,一般不需要改动。

proguard-rules.pro 是我们需要配置的规则。如果要配置多个Module的混淆文件,只需要后面添加逗号跟混淆文件路径即可。

proguard-rules.pro基本规则:
keep关键字, 保留类和类中的成员,防止它们被混淆或移除。
示例:如果不想某个类中的代码被混淆

-keep public class com.yesdk.sdk.XSDK {
    public static <fields>;
    public <methods>;
}

注意如果XSDK类中的方法含有回调,也需要把该回调方法的类也添加到keep中。
例如:XSDK下的floatWindow含有floatWindowListener回调,即:

    public void floatWindow(Activity activity, floatWindowListener listener) {
    }

那如果想CP方正常调用floatWindow方法,则需要把floatWindowListener也添加到keep当中。
示例:

-keep public class com.yesdk.sdk.XSDK {
    <fields>;
    <methods>;
}
-keep public class com.yesdk.sdk.suspendbox.floatWindowListener {
    <fields>;
    <methods>;
}

其他keep的关键字还有:
keepnames:保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
keepclassmembers:只保留类中的成员,防止它们被混淆或移除。
keepclassmembernames:只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
keepclasseswithmembers:保留类和类中的成员,防止它们被混淆或移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。
keepclasseswithmembernames:保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。

通配符:

<field>
        匹配类中的所有字段
<method>
        匹配类中的所有方法
<init>
     匹配类中的所有构造函数
    *
     匹配任意长度字符,但不含包名分隔符(.)。
     比如说我们的完整类名是com.example.test.MyActivity,使用com.*,或者com.exmaple.*都是无法匹配的,因为*无法匹配包名中的分隔符,正确的匹配方式是com.exmaple.*.*,或者com.exmaple.test.*,这些都是可以的。但如果你不写任何其它内容,只有一个*,那就表示匹配所有的东西。
    **
     匹配任意长度字符,并且包含包名分隔符(.)
    ***
     匹配任意参数类型。
     比如void set*(***)就能匹配任意传入的参数类型,*** get*()就能匹配任意返回值的类型。
  …
     匹配任意长度的任意类型参数。
     比如void test()就能匹配任意void test(String a)或者是void test(int a, String b)这些方法。

三、SDK混淆

SDK需要提供给CP方接入,提供的方式可以有 jar包、aar、maven等几种方式。这里我是采用了jar包的形式提供SDK。
但 Android Studio 是不对 jar包进行混淆的,所以需要自行使用ProGuard对jar包进行混淆。
ProGuard是一个开源的Java代码混淆器。可以在 sdk\tools\proguard\bin目录中找到,并且proguardgui.bat为它的UI界面(一般不会使用)。
ProGuard的使用:
常用语法:
从给定的文件中读取配置参数-include {filename}
指定基础目录为以后相对的档案名称-basedirectory {directoryname}// 指定要处理的应用程序jar,war,ear和目录 -injars {class_path}
指定处理完后要输出的jar,war,ear和目录的名称 -outjars {class_path}
指定要处理的应用程序jar,war,ear和目录所需要的程序库文件 -libraryjars {classpath}
指定不去忽略非公共的库类。-dontskipnonpubliclibraryclasses
指定不去忽略包可见的库类的成员。-dontskipnonpubliclibraryclassmembers

jar包进行混淆,示例代码:


def proguard() {
    def proguardDir = project.ext.proguardDir //混淆产物的输出路径(dump、mapping、seeds、usage等)
    proguard.Configuration configuration = new proguard.Configuration()
    configuration.libraryJars = new proguard.ClassPath()
    configuration.programJars = new proguard.ClassPath()
    File dir = new File(proguardDir) //如果没有这个文件夹就创建一个
    if(!dir.exists()) {
        dir.mkdirs()
    }
    configuration.dump = new File(proguardDir, 'dump.txt') 
    configuration.printMapping = new File(proguardDir, 'mapping.txt')
    configuration.printSeeds = new File(proguardDir, 'seeds.txt')
    configuration.printUsage = new File(proguardDir, 'usage.txt')

    /**
     * 获得sdk目录
     */
    def sdkDir //Android SDK的目录
    Properties properties = new Properties()
    File localProps = rootProject.file("local.properties") //读取根目录下的local.properties,判断环境是否已安装Android SDK
    if (localProps.exists()) {
        properties.load(localProps.newDataInputStream())
        sdkDir = properties.getProperty("sdk.dir")
    } else {
        sdkDir = System.getenv("ANDROID_HOME")
    }

    /**
     * 将android.jar和apache的库加入依赖
     */
    if (sdkDir) { //compileSdkVersion的版本 和 SDK目录里是否有此版本
        def compileSdkVersion = android.compileSdkVersion 
        ClassPathEntry androidEntry = new ClassPathEntry(new File("${sdkDir}/platforms/${compileSdkVersion}/android.jar"), false);
        configuration.libraryJars.add(androidEntry)
    } else {
        throw new InvalidUserDataException('$ANDROID_HOME is not defined')
    }


    File file = new File(project.ext.proguardLibraryDir) //混淆时依赖的jar包目录
    file.listFiles().each {File child -> //把目录中的jar包都添加进去
        ClassPathEntry childEntry = new ClassPathEntry(new File(child.absolutePath), false); 
        configuration.libraryJars.add(childEntry)
    }

    ClassPathEntry inJarEntry = new ClassPathEntry(new File(project.ext.rawJar), false) //未混淆的jar包路径(就是我们需要混淆的jar包的)
    configuration.programJars.add(inJarEntry)

    ClassPathEntry outJarEntry = new ClassPathEntry(new File(project.ext.proguardJar), true) //混淆完的输出路径
    configuration.programJars.add(outJarEntry)

    ConfigurationParser proguardParser = new ConfigurationParser(new File(project.ext.proguardPro)) //混淆配置文件
    proguardParser.parse(configuration)
    proguardParser.close()
    /**
     * 执行混淆
     */
    ProGuard proguard = new ProGuard(configuration)
    proguard.execute()
}

上一篇: 手游SDK-悬浮球
下一篇: 手游SDK-导出

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值