Skip to content

Android Asset 加解密 Gradle 脚本

import javax.crypto.BadPaddingException
import javax.crypto.Cipher
import javax.crypto.IllegalBlockSizeException
import javax.crypto.NoSuchPaddingException
import javax.crypto.spec.SecretKeySpec
import java.security.InvalidKeyException
import java.security.NoSuchAlgorithmException

apply plugin: 'com.android.application'

def aesKey = "\"aes0011223344key\""
def aesKeyCommon = "aes0011223344key"
def aesEnabled = true
def aesDirs = [
        (rootProject.file('app/src/main/assets')):(rootProject.file('../build/assets_tmp_dir/main_assets')),
        (rootProject.file('../assets')):(rootProject.file('../build/assets_tmp_dir/flutter_assets'))
]

android {
    defaultConfig {
        buildConfigField "String", "AES_KEY", aesKey
    }
}

void copyFolder(String oldPath, String newPath) {
    try {
        (new File(newPath)).mkdirs() //如果文件夹不存在 则建立新文件夹
        File a = new File(oldPath)
        String[] file = a.list()
        File temp = null
        for (int i = 0; i < file.length; i++) {
            if (oldPath.endsWith(File.separator)) {
                temp = new File(oldPath + file[i])
            } else {
                temp = new File(oldPath + File.separator + file[i])
            }
            if (temp.isFile()) {
                FileInputStream input = new FileInputStream(temp)
                FileOutputStream output = new FileOutputStream(newPath + "/" +
                        (temp.getName()).toString())
                byte[] b = new byte[1024 * 5]
                int len
                while ((len = input.read(b)) != -1) {
                    output.write(b, 0, len)
                }
                output.flush()
                output.close()
                input.close()
            }
            if (temp.isDirectory()) {//如果是子文件夹
                copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i])
            }
        }
    }
    catch (Exception e) {
        println("复制整个文件夹内容操作出错")
        e.printStackTrace()
    }
}

void deleteAllFilesOfDir(String path) {
    File file=new File(path)
    if (!file.exists())
        return
    if (file.isFile()) {
        file.delete()
        return
    }
    File[] files = file.listFiles()
    for (int i = 0; i < files.length; i++) {
        deleteAllFilesOfDir(files[i].getAbsolutePath())
    }
    file.delete()
}

private static byte[] encrypt(byte[] content, String password) {
    try {
        byte[] keyStr = password.getBytes()
        SecretKeySpec key = new SecretKeySpec(keyStr, "AES")
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding") //algorithmStr
        cipher.init(Cipher.ENCRYPT_MODE, key)
        byte[] result = cipher.doFinal(content)
        return result
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace()
    } catch (NoSuchPaddingException e) {
        e.printStackTrace()
    } catch (InvalidKeyException e) {
        e.printStackTrace()
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace()
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace()
    } catch (BadPaddingException e) {
        e.printStackTrace()
    }
    return null
}

private static byte[] decrypt(byte[] content, String password) {
    try {
        byte[] keyStr = password.getBytes()
        SecretKeySpec key = new SecretKeySpec(keyStr, "AES")
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
        cipher.init(Cipher.DECRYPT_MODE, key)
        byte[] result = cipher.doFinal(content)
        return result //
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace()
    } catch (NoSuchPaddingException e) {
        e.printStackTrace()
    } catch (InvalidKeyException e) {
        e.printStackTrace()
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace()
    } catch (BadPaddingException e) {
        e.printStackTrace()
    }
    return null
}

/**
 * 获得指定文件的byte数组
 */
static byte[] file2bytes(String filePath) {
    byte[] buffer = null;
    try {
        File file = new File(filePath);
        FileInputStream fis = new FileInputStream(file);
        ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
        byte[] b = new byte[1024];
        int n;
        while ((n = fis.read(b)) != -1) {
            bos.write(b, 0, n);
        }
        fis.close();
        bos.close();
        buffer = bos.toByteArray();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return buffer;
}

void encodeDir(String rawDir, String aesKey){
    println "\n===> encodeDir " + rawDir
    File searchPlug = new File(rawDir)
    if (searchPlug.exists() && searchPlug.isDirectory()) {
        File[] files = searchPlug.listFiles()
        for (File file : files) {
            if(!file.name.endsWith(".json")) { continue }
            def data= file2bytes(file.getAbsolutePath())
            def content = encrypt(data, aesKey)
            def stream = file.newOutputStream()
            stream.write(content)
            stream.flush()
            println "===> encodeDir file ok: " + file.name
        }
    }
}

gradle.addBuildListener(new BuildListener() {
    @Override
    void buildStarted(Gradle gradle) {
        println "buildStarted"
    }

    @Override
    void settingsEvaluated(Settings settings) {
        println "settingsEvaluated"
    }

    @Override
    void projectsLoaded(Gradle gradle) {
        println "projectsLoaded"
    }

    boolean canDoCrypt(Gradle gradle) {
        def taskNames = gradle.getStartParameter().taskNames
        if (taskNames.contains(":app:assembleDebug")
                || taskNames.contains(":app:assembleRelease")
                || taskNames.contains("assembleDebug")
                || taskNames.contains("assembleRelease")) {
            return true
        }
        return false
    }

    @Override
    void projectsEvaluated(Gradle gradle) {
        println "projectsEvaluated : " + gradle.getStartParameter().taskNames.toString()
        if (!aesEnabled || !canDoCrypt(gradle)) {
            return
        }
        aesDirs.eachWithIndex{ def rawDir, def tmpDir, int i ->
            //先复制加密前文件夹
            copyFolder(rawDir.absolutePath, tmpDir.absolutePath)
            encodeDir(rawDir.absolutePath, aesKeyCommon)
        }
    }

    @Override
    void buildFinished(BuildResult buildResult) {
        println "buildFinished : " + gradle.getStartParameter().taskNames.toString()
        if (!aesEnabled || !canDoCrypt(gradle)) {
            return
        }
        aesDirs.eachWithIndex{ def rawDir, def tmpDir, int i ->
            //apk打包成功后回滚文件夹
            copyFolder(tmpDir.absolutePath, rawDir.absolutePath)
            deleteAllFilesOfDir(tmpDir.absolutePath)
            println "===> recoveryDir " + rawDir.absolutePath
        }
    }
})