android插件開發,使用360加固自動多渠道打包

android插件開發,使用360加固自動多渠道打包

最近研究了一下安卓插件的開發,就以開發一個360加固自動打包插件爲例,練了一下,本次使用android studio基於kotlin構建自動打包插件.

創建插件

  • 新建一個module,選擇java\kotlin,姑且叫 JiaGuPlugin
    在這裏插入圖片描述

  • 添加依賴

    構建插件需要使用gradle依賴,build.gradle添加以下內容

     apply plugin: 'java-library'
    apply plugin: 'kotlin'
    apply plugin: 'groovy'
    
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
        implementation  gradleApi()
        implementation localGroovy()
        implementation 'com.android.tools.build:gradle:3.6.3'
    
    }
    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
    }
    sourceCompatibility = "1.8"
    targetCompatibility = "1.8"
    
    //設置maven deployer,發佈到指定目錄
    apply plugin: 'maven'
    
    repositories {
        mavenCentral()
    }
    uploadArchives {
        repositories {
            mavenDeployer {
                //設置插件的GAV參數
                pom.groupId = 'com.mml.jiagu.plugin'
                pom.artifactId = '360'
                pom.version = '1.0.0'
                //文件發佈到此模塊repo下面目錄
                repository(url: uri('repo'))
            }
        }
    }
    //發佈到本地倉庫
    apply plugin: 'maven-publish'
    publishing{
        publications{
            JiaGuPlugin(MavenPublication){
                 from components.java
                groupId 'com.mml.jiagu.plugin'
                artifactId '360'
                version '1.1'
            }
        }
    }
    
  • 創建一個配置擴展類

    用於存儲360加固配置
    使用kotlin創建的bean 不能使用data class 創建,因爲是final類型的,在實例化時將不能讀取,故創建一個開放的普通類

    package com.mml.jiagu.plugin
    
    open class JiaGuPluginExtension {
    
        var jiaGuToolsPath: String? = null
        var username: String? = null
        var password: String? = null
        var keyStoreFile: String? = null
        var keyStorePassword: String? = null
        var keyAlias: String? = null
        var keyAliasPassword: String? = null
        var channelFile: String? = null
        var inputFile: String? = null
        var outputFile: String? = null
        var config:Array<String>? = null
    }
    
  • 創建 task

    創建執行的任務具體內容

    package com.mml.jiagu.plugin
    
    import org.gradle.api.DefaultTask
    import org.gradle.api.tasks.TaskAction
    import java.io.*
    import javax.inject.Inject
    
    /**
     * Author: Menglong Ma
     * Email: [email protected]
     * Date: 2020/4/24 18:30
     * Description: This is JiaGuTask
     * Package: com.mml.jiagu.plugin
     * Project: DeskTopPhotoView
     */
    //使用kotlin 需要聲明類open
    open class JiaGuTask() : DefaultTask() {
        lateinit var apk: File
        lateinit var jiaGuPluginExtension: JiaGuPluginExtension
    	//@Inject task的入口
        @Inject
        constructor(apk: File, jiaGuPluginExtension: JiaGuPluginExtension) : this() {
            group = JiaGuPlugin.GROUP
            description = " 360 jiagu"
            this.apk = apk
            this.jiaGuPluginExtension = jiaGuPluginExtension
        }
    	//  @TaskAction 標註,雙擊執行這個任務時調用這個方法
        @TaskAction
        fun begin() {
        	//參照360加固文檔編寫相應的命令
            println("login 360 account")
            project.exec { execSpec ->
                execSpec.commandLine(
                    "java", "-jar", jiaGuPluginExtension.jiaGuToolsPath,
                    "-login", jiaGuPluginExtension.username, jiaGuPluginExtension.password
                )
            }
            println("import sign")
            project.exec { execSpec ->
                execSpec.commandLine(
                    "java",
                    "-jar",
                    jiaGuPluginExtension.jiaGuToolsPath,
                    "-importsign",
                    jiaGuPluginExtension.keyStoreFile,
                    jiaGuPluginExtension.keyStorePassword
                    ,
                    jiaGuPluginExtension.keyAlias,
                    jiaGuPluginExtension.keyAliasPassword
                )
            }
            jiaGuPluginExtension.channelFile?.let {
                println("import mulpkg")
                project.exec { execSpec ->
                    execSpec.commandLine(
                        "java", "-jar", jiaGuPluginExtension.jiaGuToolsPath,
                        "-importmulpkg", it
                    )
                }
            }
            jiaGuPluginExtension.config?.let {
                println("config ")
                project.exec { execSpec ->
                    execSpec.commandLine(
                        "java", "-jar", jiaGuPluginExtension.jiaGuToolsPath,
                        "--config", it
                    )
                }
            }
            println("origin apk.absolutePath:${apk.absolutePath}")
            println("source apk.absolutePath:${apk.parent}")
            project.exec { execSpec ->
                execSpec.commandLine(
                    "java", "-jar", jiaGuPluginExtension.jiaGuToolsPath,
                    "-jiagu",
                    jiaGuPluginExtension.inputFile ?: apk.absolutePath,
                    jiaGuPluginExtension.outputFile ?: apk.parent, "-autosign",
                    "${jiaGuPluginExtension.channelFile?.let { "-automulpkg" }}"
                )
            }
        }
    
    }
    
  • 創建plugin
    繼承 Plugin 接口,實現apply方法
    main目錄下創建插件配置,路徑沒有就創建,並且不可更改resources/META-INF/gradle-plugins/com.mml.jiagu.plugin.properties,其中com.mml.jiagu.plugin表示應用時的名字,如:apply plugin: 'com.mml.jiagu.plugin'

    //配置很簡單,插件的全類名限定路徑
     implementation-class=com.mml.jiagu.plugin.JiaGuPlugin
    
    //插件類
    package com.mml.jiagu.plugin
    
    
    import com.android.build.gradle.AppExtension
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    
    
    public class JiaGuPlugin : Plugin<Project> {
        companion object {
            val GROUP = "JiaGu"
            //app build.gradle 中使用的名字 jiagu{xxx xxx}
            val EXTENSION_NAME = "jiagu"
        }
    
        private val taskMap = mutableMapOf<String,String>()
        override fun apply(project: Project) {
        //讀取360加固配置
            val jiaGuPluginExtension = project.extensions
                .create(EXTENSION_NAME, JiaGuPluginExtension::class.java)
            val isResguard = project.plugins.hasPlugin("AndResGuard")
            project.afterEvaluate { project ->
                println("afterEvaluate ${jiaGuPluginExtension.jiaGuToolsPath}")
                val appExtension = project.extensions.getByType(AppExtension::class.java)
                appExtension.applicationVariants.all { applicationVariant ->
                    val flavorName= applicationVariant.flavorName
                    applicationVariant.outputs.all {
                        val outputFile = it.outputFile
                        //println("outputFile:${outputFile.absolutePath}")
                        val jiaGuName = "jiagu-${it.name}"
                        println("create task:$jiaGuName")
                        val jiaGuTask = project.tasks.create(
                            jiaGuName,
                            JiaGuTask::class.java,
                            outputFile,
                            jiaGuPluginExtension
                        )
                        val buildAndJiaGuName = "build-and-$jiaGuName"
                        println("create task:$buildAndJiaGuName")
                        taskMap[buildAndJiaGuName] = "assemble$flavorName"
                        val buildAndJiaGuTask = project.tasks.create(
                            buildAndJiaGuName,
                            JiaGuTask::class.java,
                            outputFile,
                            jiaGuPluginExtension
                        )
                        buildAndJiaGuTask.doFirst {
                            println("${it.name} doFirst")
                        }
                        buildAndJiaGuTask.doLast {
                            println("${it.name} doLast")
                        }
                        buildAndJiaGuTask.dependsOn("assemble$flavorName")
    
                    }
    
                }
            }
            project.tasks.whenTaskAdded {task ->
                println("whenTaskAdded:${task.name} dependsOn ${task.dependsOn}")
                val get=taskMap[task.name]
                get?.let {
                    println("task ${task.name} dependsOn $it")
                    task.dependsOn(it)
                }
    
            }
        }
    
    }
    
    

測試插件

  • 發佈本地倉庫

    編寫完成插件,可在gradle命令集中發現以下命令publishing和upload,分別對應build.gradle裏的兩個發佈本地任務,執行gradle 命令發佈本地.
    >發佈命令
    發佈成功

  • 項目引用
    發佈本地成功以後,即可進行使用,在project build.gradle中引用

       repositories {
            google()
            jcenter()
            //本地倉庫
            mavenLocal()
            //指定倉庫
            maven {
                url uri("JiaGuPlugin/repo")
            }
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:3.6.3'
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
            //引用相應倉庫中的包
           // classpath 'com.mml.jiagu.plugin:360:1.0.0'
            classpath 'com.mml.jiagu.plugin:360:1.1'
    
        }
    
  • 在app build.gradle中使用插件
    添加以下帶,構建完成以後會在項目任務集中發現jiagu任務
    在這裏插入圖片描述

    apply plugin: 'com.mml.jiagu.plugin'
    
    String os = "${project.rootDir.absolutePath}/BaseWheelsByKotlin/JiaGuPlugin/tools/${getJiaguJarFilePathByOs()}"
    jiagu {
        jiaGuToolsPath "${os}/jiagu.jar"
        username "XXX"
        password "XXX"
        keyStoreFile android.signingConfigs.release.storeFile.absolutePath
        keyStorePassword android.signingConfigs.release.storePassword
        keyAlias android.signingConfigs.release.keyAlias
        keyAliasPassword android.signingConfigs.release.keyPassword
        inputFile //"${buildDir.getAbsolutePath()}\\outputs\\apk\\release\\app-release.apk"
        outputFile //"${buildDir.getAbsolutePath()}\\jiagu" //這裏指定的是輸出文件夾
        config '-so', '-data', '-assets', '-string_obfus', '-so_private'
        channelFile "${os}/多渠道模板.txt"
    }
    
    String getJiaguJarFilePathByOs(){
        String osName = org.gradle.internal.os.OperatingSystem.current().getName();
        String osVersion = org.gradle.internal.os.OperatingSystem.current().getVersion();
        println "*** $osName $osVersion was detected."
    
        if (org.gradle.internal.os.OperatingSystem.current().isLinux()) {
            println("Linux")
            return "linux"+File.separator+"jiagu"
        } else if (org.gradle.internal.os.OperatingSystem.current().isWindows()) {
            println("Windows")
            return "windows"+File.separator+"jiagu"
        } else if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
            println("OSX")
            return "mac"+File.separator+"jiagu"
        }
    }
    

最後,放上demo鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章