未經(jīng)允許禁止轉載
一听想、寫這篇文章的原因
在平日開發(fā)中蛮艰,我們時常是需要保存一些字符串,而這些字符串比較重要窍侧,我們可以通過一些途徑進行保存</br>
(1)通過網(wǎng)絡分發(fā)動態(tài)的密碼,以及對應的加密的字符串转绷,在一定時間內密碼有效伟件。
(2)密碼本地存儲在一些地方,如SP议经,數(shù)據(jù)庫斧账,MMKV,動態(tài)鏈接庫等等
本文就基于第二種方案中的動態(tài)鏈接庫去進行開發(fā)煞肾,即我們俗稱的So庫咧织,由于不存在百分百解不開的加密方式,都是時間長和短的問題籍救,我們要增加的是解密的時間成本习绢,而且考慮到開發(fā)時候的方便以及性能問題,我們都采用多種結合蝙昙,例如 網(wǎng)路+本地秘鑰雙重校驗闪萄,或者動態(tài)分發(fā)加密關鍵信息再組合等等。
二耸黑、Gradle Plugin開發(fā)
1桃煎、建一個Module
2、Grdlde基本配置
假設我們的Module名字是plugin,那么在Project根目錄的中,修改引入方法
//include(":plguin") 改成下面
includeBuild("plguin")
本項目基于kotlin開發(fā)的所以需要把build.gradle修改為build.gradle.kts文件</br>
大致的配置如下:
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21")
}
}
dependencies {
compileOnly(gradleApi())
compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21")
compileOnly("com.android.tools.build:gradle:4.0.1")
implementation("com.squareup:javapoet:1.13.0") //用于生產(chǎn)JAVA代碼
}
gradlePlugin {
plugins {
create(Plugin的名字大刊,自己定義) {
id = "自己定義獨立Id"
implementationClass = "對應的Plugin的路徑为迈,即包名.類名"
}
}
}
其中“org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21” 可以修改為 “kotlin-dsl”
主要是為了導入Kotlin開發(fā)Gradle Plugin的基礎環(huán)境, "com.squareup:javapoet:1.13.0" 用于生產(chǎn)自定義的JAVA代碼,動態(tài)生成代碼處理我們儲存的內容缺菌。
如何實現(xiàn)實現(xiàn)獨立存在:app和:Library
1葫辐、自己生成CMakeLists文件
如果有NDK開發(fā)經(jīng)驗都應該知道,我們需要一個CMakeLists.txt文件去構建混合了Native C++的項目伴郁,而這個CMakeLists.txt很容易存在沖突等問題耿战,包括同名的動態(tài)鏈接庫也是,所以我們利用Gradle的Task任務進行焊傅,動態(tài)生成CMakeLists.txt,并且So庫的名字也是不同名字剂陡,內容大致如下:
cmake_minimum_required(VERSION 3.4.1)
add_library(
core-client //你的.So庫名字狈涮,就是,生成結果是libcore-client.so文件鸭栖,System.loadLibrary("core-client")
SHARED
src/main/cpp/core-client.cpp
src/main/cpp/core-environment.cpp
src/main/cpp/core-encryption.cpp
)
find_library(
log-lib
log )
target_link_libraries(
core-client //你的.So庫名字
${log-lib} )
有了這個關鍵因素那么我們就可以解決重復名字的.So庫的問題了歌馍,自己改了這個名字,讓互不干擾晕鹊。
2松却、如何把Nativce方法動態(tài)綁定到我們的JAVA文件
既然我們的.So是獨立的那么,我們調用這些方法的JAVA文件最好也是獨立一個溅话,這時候又要兼容app和libray的存在晓锻,就會出現(xiàn)包名路徑不同,如果單純的傳統(tǒng)的native方法自動生成代碼的不可行了
extern "C"
包_名_XXX_XXX_XX_名字(JNIEnv *env,jclass clazz)
這種不能滿足我們的要求飞几,我們需要動態(tài)注冊方法
jint JNI_OnLoad(JavaVM *vm, void *reserved)// System.loadLibrary("") 加載
那我就在這里注冊方法
extern "C"
JNIEXPORT jstring JNICALL getString(JNIEnv *env,jclass clazz,jstring key_){
return env->NewStringUTF(result);
}
JNINativeMethod methods[] = {
{ "getString", "(Ljava/lang/String;)Ljava/lang/String;",(void*)getString},
};
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
env->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(JNINativeMethod));
return JNI_VERSION_1_6;
}
//對應JAVA的方法
public static native String getString(String key);
這個JNINativeMethod methods[]其實很好理解砚哆,第一個是方法名字,第二個是(參數(shù))和返回值(return = what?),第三個指向的實現(xiàn)方法
具體怎么填寫循狰,這里也不展開細講窟社。找到這篇參考文章
3、支持兩種加密方式
本項目采用最簡單的兩種對稱加密方式:AES和DES
具體調用
由于庫我已經(jīng)上傳到Jitpack了,所以需要在根目錄的project中配置環(huán)境
buildscript {
repositories {
google()
jcenter()
maven { setUrl("https://jitpack.io") }
}
dependencies {
classpath("com.occ.orca:orca.so:2.0.0-release13")
}
}
然后在項目的module和app中build.gradle添加
plugins {
id 'com.android.application'
id 'Orca' //必須先于kotlin-android 后于com.android.application
id 'kotlin-android'
}
使用也很方便绪钥,在項目或者模塊的build.gradle的里書寫
android{
Orca.go{
isDebug = true //默認值為false灿里,必須輸入Signature
encryptMode = "des" // 輸入AES或者DES,不用區(qū)分大小寫
storeSet{
"data"{
value = "4444444444"
}
"1223"{
value = "888888" //命名數(shù)字開頭程腹,方法名會有下劃線
}
}
}
}
//這是我們調用的地方匣吊,注意CoreClient有包名的區(qū)分,不是把所有結果集合到同一個類里
val data = CoreClient.getData()
val data1 = CoreClient.get_1223()
4寸潦、使用注意
代碼在C++層中色鸳,進行了判斷簽名的校驗,如果簽名校驗錯誤會直接崩潰见转,字段為secretKey命雀,而你們加密的所用到的Key則為字段signature,而控制是否輸入signature由isDebug字段進行控制,都是小駝峰寫法斩箫。
小結
本項目采用的AESEncryption和DESEncryption吏砂,提出的方案還有很多需要完善的處理,后續(xù)會考慮直接在C++層做加密的運算乘客,歡迎各位Pull Request.