├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zeno │ │ └── encryptanddecrypt │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── HelloNDK.c │ │ ├── util.c │ │ ├── util.h │ │ └── utils.c │ ├── java │ │ └── com │ │ │ └── zeno │ │ │ └── encryptanddecrypt │ │ │ ├── MainActivity.java │ │ │ └── ndk │ │ │ └── HelloNDK.java │ ├── jni │ │ └── hellondk.c │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── zeno │ └── encryptanddecrypt │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EncryptAndDecrypt 2 | EncryptAndDecrypt , 文件加密解密与分割合并 3 | 4 | 接续上篇[NDK开发基础①使用Android Studio编写NDK](http://www.jianshu.com/p/f1b8b97d2ef8) 5 | 6 | ### 前情提要 7 | 随着Android Studio的越来越完善 , 我们编写NDK就会越来越方便,使用Android Studio 2.2 RC2 , 编写NDK的时候 , 不需要使用`javah`命令来生成头文件 , 创建一个`native`方法 , 使用`alt + enter`会提示要你创建一个JNI函数 , C/C++语法提示也相对比较完善了, 减少了一些重复代码的编写,相信使用Android Studio 2.2编写NDK, 不会让你失望 。 8 | 9 | ###Part 1 , -- 文件的加密解密 10 | 在[C语言基础系列](http://www.jianshu.com/p/4701cd1e1914)第八章[文件IO](http://www.jianshu.com/p/eb5d58800a63),介绍了文件的加密解密 , 开发工具使用的是VS , 在上篇[NDK开发基础①使用Android Studio编写NDK](http://www.jianshu.com/p/f1b8b97d2ef8)简单介绍了Android Studio来搭建NDK开发环境,今天我们使用Android Studio来玩一把 。 11 | 12 | > 界面 与Project目录结构 13 | 14 | ![UI](http://upload-images.jianshu.io/upload_images/643851-788b88eea0671dba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 15 | 16 | 就几个按钮 , 布局文件就不贴代码了 , 读者也可以整个输入框,可以输入加密的密码 。 17 | 18 | 19 | ![project directory](http://upload-images.jianshu.io/upload_images/643851-d44584946c363713.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 20 | 21 | 从目录上可以看出`ndk`包下面的 , 就是一个`native`方法的类, `cpp`目录下的就是JNI `C`文件 , CMakeLists.txt配置我们的编译流程,以及生成库与添加库的配置。 22 | 23 | > Java native code 24 | 25 | ```java 26 | /** 27 | * 带密码的文件加密 28 | * @param normalFilePath 要加密的文件路径 29 | * @param encryptFilePath 加密之后的文件路径 30 | * @param password 加密密码 31 | */ 32 | public static native void fileEncrypt(String normalFilePath,String encryptFilePath,String password) ; 33 | 34 | /** 35 | * 带密码的文件解密 36 | * @param encryptFilePath 要解密的文件路径 37 | * @param encryptFilePath 解密之后的文件路径 38 | * @param password 加密密码 39 | */ 40 | public static native void fileDecrypt(String encryptFilePath,String decryptFilePath,String password) ; 41 | ``` 42 | 简要提示:文件的加密解密 , 实质上在复制文件的时候进行`^`运算,在计算机中 , 所有的文件都是以二进制存储的 , 所有可以进行运算来进行文件的加密解密 , 当然 , 密码的算法是可逆的 , 也就是可解密的 。 43 | 44 | > use java native code 45 | 46 | ```java 47 | // SD_CARD 根路径 48 | private static final String SD_CARD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() ; 49 | 50 | /*文件加密*/ 51 | private void fileEncrypt() { 52 | String normalFilePath = SD_CARD_PATH+ File.separatorChar+"neck.jpg" ; 53 | String encryptFilePath = SD_CARD_PATH+File.separatorChar+"neck_encrypt.jpg" ; 54 | Log.e(TAG, "fileEncrypt: normalFilePath = "+ normalFilePath + " encryptFilePath = "+encryptFilePath); 55 | 56 | try{ 57 | HelloNDK.fileEncrypt(normalFilePath,encryptFilePath,"xj"); 58 | }catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | 62 | } 63 | 64 | /*文件解密*/ 65 | private void fileDecrypt() { 66 | 67 | String encryptFilePath = SD_CARD_PATH+File.separatorChar+"neck_encrypt.jpg" ; 68 | String decryptFilePath = SD_CARD_PATH+File.separatorChar+"neck_decrypt.jpg" ; 69 | 70 | try{ 71 | HelloNDK.fileDecrypt(encryptFilePath,decryptFilePath,"xj"); 72 | }catch (Exception e) { 73 | e.printStackTrace(); 74 | } 75 | } 76 | ``` 77 | 78 | > 文件加密解密实现 79 | 80 | ```c 81 | /*加密文件*/ 82 | JNIEXPORT void JNICALL 83 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_fileEncrypt(JNIEnv *env, jclass type, 84 | jstring normalFilePath_, 85 | jstring encryptFilePath_, 86 | jstring password_) { 87 | const char *normalFilePath = (*env)->GetStringUTFChars(env, normalFilePath_, 0); 88 | const char *encryptFilePath = (*env)->GetStringUTFChars(env, encryptFilePath_, 0); 89 | const char *password = (*env)->GetStringUTFChars(env, password_, 0); 90 | 91 | 92 | int passwordLen = strlen(password); 93 | 94 | LOGE("MainActivity","path1 == %s , path2 == %s",normalFilePath , encryptFilePath) ; 95 | 96 | // 读文件指针 97 | FILE* frp = fopen(normalFilePath,"rb") ; 98 | // 写文件指针 99 | FILE* fwp = fopen(encryptFilePath,"wb") ; 100 | 101 | if(frp == NULL) { 102 | LOGE("MainActivity","%s","文件不存在") ; 103 | return; 104 | } 105 | if(fwp == NULL) { 106 | LOGE("MainActivity","%s","没有写权限") ; 107 | } 108 | 109 | // 边读边写边加密 110 | int buffer ; 111 | int index = 0 ; 112 | while((buffer = fgetc(frp)) != EOF) { 113 | 114 | // write 115 | fputc(buffer ^ *(password+(index % passwordLen)),fwp) ; 116 | index++ ; 117 | } 118 | 119 | 120 | // 关闭文件流 121 | fclose(fwp); 122 | fclose(frp); 123 | 124 | LOGE("MainActivity","%s","文件加密成功") ; 125 | 126 | (*env)->ReleaseStringUTFChars(env, normalFilePath_, normalFilePath); 127 | (*env)->ReleaseStringUTFChars(env, encryptFilePath_, encryptFilePath); 128 | (*env)->ReleaseStringUTFChars(env, password_, password); 129 | } 130 | ``` 131 | 简要提示:加密解密算法,在[C语言:文件IO](http://www.jianshu.com/p/eb5d58800a63)里面就介绍了 , 这里就不加赘述了,加密与解密共用的是一套算法, 解密的就不贴代码了 。在使用`*password`指针的时候需要注意,`password+1`可以得到下一个字符,但是`password+0`的时候不会得到第一个字符,会输出整个字符指针,所有在使用字符指针的时候一个一个取字符 , 需要使用`*(password+0) ,*(password+1) `取第一个第二字符 。如果您对C语言以及JNI开发都不了解的话 , 可以关注的我的专题[Android NDK开发之旅](http://www.jianshu.com/collection/a25bf14495d7) 132 | 133 | ### Part 2 , 文件分割与合并 134 | 135 | __使用场景:__大文件上传 , 如视频文件 , 进行文件拆分 , 分批上传 。 136 | 137 | > Java native code 138 | 139 | ```java 140 | /** 141 | * 文件分割 142 | * @param splitFilePath 要分割文件的路径 143 | * @param suffix 分割文件拓展名 144 | * @param fileNum 分割文件的数量 145 | */ 146 | public static native void fileSplit(String splitFilePath,String suffix,int fileNum); 147 | 148 | /** 149 | * 文件合并 150 | * @param splitFilePath 分割文件的路径 151 | * @param splitSuffix 分割文件拓展名 152 | * @param mergeSuffix 合并文件的拓展名 153 | * @param fileNum 分割文件的数量 154 | */ 155 | public static native void fileMerge(String splitFilePath,String splitSuffix,String mergeSuffix,int fileNum); 156 | ``` 157 | > use java native code 158 | 159 | ```java 160 | /*分割文件*/ 161 | private void fileSplit() { 162 | String splitFilePath = SD_CARD_PATH+File.separatorChar+"neck.jpg" ; 163 | String suffix = ".b"; 164 | try{ 165 | HelloNDK.fileSplit(splitFilePath,suffix,3); 166 | }catch (Exception e) { 167 | e.printStackTrace(); 168 | } 169 | 170 | } 171 | 172 | /*文件合并*/ 173 | private void fileMerge() { 174 | String splitFilePath = SD_CARD_PATH+File.separatorChar+"neck.jpg" ; 175 | String splitSuffix = ".b"; 176 | String mergeSuffix = ".jpeg"; 177 | try{ 178 | HelloNDK.fileMerge(splitFilePath,splitSuffix,mergeSuffix,3); 179 | }catch (Exception e) { 180 | e.printStackTrace(); 181 | } 182 | } 183 | ``` 184 | 185 | > 文件分割实现 186 | 187 | 算法分析图: 188 | 189 | ![file split](http://upload-images.jianshu.io/upload_images/643851-3348bb0d653afe62.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 190 | 191 | 伪代码: 192 | ``` 193 | // 平均分配文件大小 194 | if(fileSize % fileNum) { 195 | int i= 0 ; 196 | for(; i < fileNum ; i++) { 197 | // 创建分割文件 198 | int j= 0 ; 199 | for(;j < partFileSize ; j++) { 200 | // 读写数据 201 | } 202 | 203 | } 204 | } 205 | // 不可平均分配大小 206 | else { 207 | // 前面的文件平分文件大小 , 将剩下的大小全部给最后一个文件 208 | if(fileSize % (fileNum-1)){ 209 | int i= 0 ; 210 | for(; i < (fileNum-1) ; i++) { 211 | // 创建分割文件 212 | int j= 0 ; 213 | for(;j < partFileSize ; j++) { 214 | // 读写数据 215 | } 216 | } 217 | 218 | }else { 219 | // 将剩余大小fileSize % (fileNum-1)写入到最后一个文件中 220 | int j = 0 ; 221 | for(;j < fileSize % (fileNum-1)){ 222 | // 读写数据 223 | } 224 | 225 | } 226 | } 227 | ``` 228 | 文件分割算法就分析到这里 , 下面我们来看看具体的实现: 229 | 230 | > java native code 231 | 232 | ```java 233 | /*分割文件*/ 234 | private void fileSplit() { 235 | String splitFilePath = SD_CARD_PATH+File.separatorChar+"neck.jpg" ; 236 | String suffix = ".b"; 237 | try{ 238 | HelloNDK.fileSplit(splitFilePath,suffix,3); 239 | }catch (Exception e) { 240 | e.printStackTrace(); 241 | } 242 | 243 | } 244 | 245 | /*文件合并*/ 246 | private void fileMerge() { 247 | String splitFilePath = SD_CARD_PATH+File.separatorChar+"neck.jpg" ; 248 | String splitSuffix = ".b"; 249 | String mergeSuffix = ".jpeg"; 250 | try{ 251 | HelloNDK.fileMerge(splitFilePath,splitSuffix,mergeSuffix,3); 252 | }catch (Exception e) { 253 | e.printStackTrace(); 254 | } 255 | } 256 | ``` 257 | 258 | > 具体实现: 259 | 260 | ```c 261 | /*文件分割*/ 262 | JNIEXPORT void JNICALL 263 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_fileSplit(JNIEnv *env, jclass type, 264 | jstring splitFilePath_, 265 | jstring suffix_, 266 | jint fileNum) { 267 | const char *splitFilePath = (*env)->GetStringUTFChars(env, splitFilePath_, 0); 268 | const char *suffix = (*env)->GetStringUTFChars(env, suffix_, 0); 269 | 270 | // 要分割文件 , 首先要得到分割文件的路径列表 ,申请动态内存存储路径列表 271 | char** split_path_list = (char**)malloc(sizeof(char*) * fileNum); 272 | 273 | // 得到文件大小 274 | long file_size = getFileSize(splitFilePath); 275 | 276 | // 得到路径字符长度 277 | int file_path_str_len = strlen(splitFilePath); 278 | 279 | // 组合路径 280 | char file_path[file_path_str_len + 5] ; 281 | strcpy(file_path,splitFilePath); 282 | strtok(file_path,"."); 283 | strcat(file_path,"_%d"); 284 | strcat(file_path,suffix); 285 | 286 | int i=0 ; 287 | for (; i < fileNum; ++i) { 288 | 289 | // 申请单个文件的路径动态内存存储 290 | split_path_list[i] = (char*)malloc(sizeof(char) * 128); 291 | // 组合分割的单个文件路径 292 | sprintf(split_path_list[i],file_path,(i+1)) ; 293 | 294 | LOGE("MainActivity","%s",split_path_list[i]); 295 | } 296 | 297 | 298 | 299 | LOGE("MainActivity","文件大小 == %ld",file_size); 300 | LOGE("MainActivity","文件路径 == %s",splitFilePath); 301 | // 读文件 302 | FILE* fp = fopen(splitFilePath,"rb"); 303 | if(fp == NULL) { 304 | LOGE("MainActivity","%s","文件不存在,或文件不可读"); 305 | return; 306 | } 307 | 308 | // 整除 , 说明各个文件划分大小一致 309 | if (file_size % fileNum) { 310 | // 单个文件大小 311 | int part_file_size = file_size/fileNum ; 312 | LOGE("MainActivity","单个文件大小 == %d",part_file_size); 313 | int i = 0 ; 314 | // 分割多少个文件就分段读多少次 315 | for (; i < fileNum; i++) { 316 | // 写文件 317 | FILE* fwp = fopen(split_path_list[i],"wb"); 318 | if(fwp == NULL) { 319 | LOGE("MainActivity","%s","没有文件写入权限"); 320 | return; 321 | } 322 | int j = 0 ; 323 | // 单个文件有多大 , 就读写多少次 324 | for (; j < part_file_size; j++) { 325 | // 边读边写 326 | fputc(fgetc(fp),fwp) ; 327 | } 328 | 329 | // 关闭文件流 330 | fclose(fwp); 331 | } 332 | } 333 | /*文件大小不整除*/ 334 | else{ 335 | // 不整除 336 | int part_file_size = file_size / (fileNum -1 ) ; 337 | LOGE("MainActivity","单个文件大小 == %d",part_file_size); 338 | int i = 0 ; 339 | for (; i < (fileNum - 1); i++) { 340 | // 写文件 341 | FILE* fwp = fopen(split_path_list[i],"wb"); 342 | 343 | if(fwp == NULL) { 344 | LOGE("MainActivity","%s","没有文件写入权限") ; 345 | return; 346 | } 347 | 348 | int j = 0 ; 349 | for (; j < part_file_size; j++) { 350 | // 边读边写 351 | fputc(fgetc(fp),fwp); 352 | } 353 | 354 | // 关闭流 355 | fclose(fwp); 356 | } 357 | 358 | // 剩余部分 359 | FILE* last_fwp = fopen(split_path_list[fileNum - 1],"wb") ; 360 | i= 0 ; 361 | for (; i < file_size % (fileNum -1); i++) { 362 | fputc(fgetc(fp),last_fwp) ; 363 | } 364 | 365 | // 关闭流 366 | fclose(last_fwp); 367 | 368 | } 369 | 370 | 371 | // 关闭文件流 372 | fclose(fp); 373 | 374 | // 释放动态内存 375 | i= 0 ; 376 | for (; i < fileNum ; i++) { 377 | free(split_path_list[i]) ; 378 | } 379 | 380 | free(split_path_list); 381 | 382 | (*env)->ReleaseStringUTFChars(env, splitFilePath_, splitFilePath); 383 | (*env)->ReleaseStringUTFChars(env, suffix_, suffix); 384 | } 385 | ``` 386 | 简要提示:组合路径的时候,使用了`strtok`来进行文件路径的分割,将`.jpg`去掉,用`strcat`拼接了`_%d`,最后拼接了传入的文件拓展名,这样设计是为了让分割的文件 , 不那么见名知意 。 387 | `LOGE`定义的一个预处理函数,在C语言基础系列[C语言基础及指针⑩预编译及jni.h分析](http://www.jianshu.com/p/569f968bcdce)有着详细说明。 388 | 389 | ```c 390 | #define LOGE(TAG,FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,TAG,FORMAT,__VA_ARGS__) 391 | ``` 392 | 393 | > 文件合并 394 | 395 | 文件的分割 , 是件一个文件分割成多个子文件 。文件的合并 , 则是将多个子文件合并成一个文件 。 396 | 397 | 算法分析图: 398 | 399 | ![merge file](http://upload-images.jianshu.io/upload_images/643851-fa3ebc68a92c3958.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 400 | 401 | > 具体实现 402 | 403 | ```c 404 | 405 | 406 | /*合并文件*/ 407 | JNIEXPORT void JNICALL 408 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_fileMerge(JNIEnv *env, jclass type, 409 | jstring splitFilePath_, 410 | jstring splitSuffix_, 411 | jstring mergeSuffix_, jint fileNum) { 412 | const char *splitFilePath = (*env)->GetStringUTFChars(env, splitFilePath_, 0); 413 | const char *splitSuffix = (*env)->GetStringUTFChars(env, splitSuffix_, 0); 414 | const char *mergeSuffix = (*env)->GetStringUTFChars(env, mergeSuffix_, 0); 415 | 416 | // 1. 申请split文件路径列表动态内存 417 | char** split_path_list = (char**)malloc(sizeof(char*) * fileNum) ; 418 | 419 | 420 | // 2. 组装split文件路径 421 | int split_file_path_len = strlen(splitFilePath) ; 422 | int split_file_path_suffix_len = strlen(splitSuffix); 423 | char split_file_path[split_file_path_len + split_file_path_suffix_len] ; 424 | strcpy(split_file_path,splitFilePath); 425 | strtok(split_file_path,"."); 426 | strcat(split_file_path,"_%d"); 427 | strcat(split_file_path,splitSuffix); 428 | 429 | // 3. 组装merge文件路径 430 | int merge_file_path_len = strlen(mergeSuffix); 431 | char merge_file_path[split_file_path_len + merge_file_path_len] ; 432 | strcpy(merge_file_path,splitFilePath); 433 | strtok(merge_file_path,"."); 434 | strcat(merge_file_path,mergeSuffix); 435 | 436 | LOGE("MainActivity","merge 文件路径 = %s",merge_file_path) ; 437 | 438 | // 4. 循环得到split文件路径列表 439 | int file_path_str_len = strlen(split_file_path); 440 | int i= 0; 441 | for (; i < fileNum; i++) { 442 | split_path_list[i] = (char*)malloc(sizeof(char) * file_path_str_len) ; 443 | 444 | sprintf(split_path_list[i],split_file_path,(i+1)) ; 445 | 446 | LOGE("MainActivity","split文件路径列表 = %s",split_path_list[i]) ; 447 | } 448 | 449 | // 5. 创建并打开 merge file 450 | FILE* merge_fwp = fopen(merge_file_path,"wb") ; 451 | 452 | // 6. 边读边写 , 读多个文件,写入一个文件 453 | i = 0 ; 454 | for (; i < fileNum ; i++) { 455 | 456 | FILE* split_frp = fopen(split_path_list[i],"rb") ; 457 | if(split_frp == NULL) { 458 | LOGE("MainActivity","%s","文件不存在,或没有读文件权限"); 459 | return; 460 | } 461 | long part_split_file_size = getFileSize(split_path_list[i]); 462 | int j = 0 ; 463 | for (; j < part_split_file_size; j++) { 464 | fputc(fgetc(split_frp),merge_fwp); 465 | } 466 | 467 | // 关闭流 468 | fclose(split_frp) ; 469 | 470 | // 每合并一个文件 ,就删除它 471 | remove(split_path_list[i]) ; 472 | } 473 | 474 | // 关闭文件流 475 | fclose(merge_fwp); 476 | 477 | // 释放动态内存 478 | i = 0 ; 479 | for (; i < fileNum; i++) { 480 | free(split_path_list[i]) ; 481 | } 482 | 483 | free(split_path_list); 484 | 485 | LOGE("MainActivity","%s","文件合并完成") ; 486 | 487 | (*env)->ReleaseStringUTFChars(env, splitFilePath_, splitFilePath); 488 | (*env)->ReleaseStringUTFChars(env, splitSuffix_, splitSuffix); 489 | (*env)->ReleaseStringUTFChars(env, mergeSuffix_, mergeSuffix); 490 | } 491 | ``` 492 | 简要提示:在编写文件分割与合并的时候 , 文件的路径千万不要弄混了,笔者有有时候也会因为变量的提示没细看 , 而将分割的子文件路径与目标文件路径弄混 ,在命名的时候 , 尽量规范 , 见名知意 。在发生错误的时候 , 一步一步的调试 , 首先猜测哪里发生异常的可能性比较大 , 再进行log输出查看 。 493 | 494 | ### 结语 495 | 文件的加密解密 , 可以引申为对数据的加密解密 , 可以使用C/C++进行加密解密, 这样对反编译APK增加了难度 , 也多了一层防范 , 因为java实在是太容易反编译了, 即使不反编译成java代码, 通过smail文件也可以看个大概 , 还是很危险的 。 496 | 497 | 文件的分割与合并 , 对文件数据传输有很大益处 。 498 | 499 | > 如果想了解更多关于Android NDK的知识 , 欢迎关注我的专题[Android NDK 开发之旅](http://www.jianshu.com/collection/a25bf14495d7) , 从零开始 , 带你一步一步进入NDK开发的世界 。 500 | 501 | ### 参考 502 | [Standard C 语言标准函数库速查](http://ganquan.info/standard-c/function/tmpnam) 503 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Sets the minimum version of CMake required to build the native 2 | # library. You should either keep the default value or only pass a 3 | # value of 3.4.0 or lower. 4 | 5 | cmake_minimum_required(VERSION 3.4.1) 6 | 7 | 8 | 9 | # Creates and names a library, sets it as either STATIC 10 | # or SHARED, and provides the relative paths to its source code. 11 | # You can define multiple libraries, and CMake builds it for you. 12 | # Gradle automatically packages shared libraries with your APK. 13 | 14 | add_library( # Sets the name of the library. 15 | HelloNDK 16 | 17 | # Sets the library as a shared library. 18 | SHARED 19 | 20 | # Provides a relative path to your source file(s). 21 | # Associated headers in the same location as their source 22 | # file are automatically included. 23 | src/main/cpp/HelloNDK.c ) 24 | 25 | # Searches for a specified prebuilt library and stores the path as a 26 | # variable. Because system libraries are included in the search path by 27 | # default, you only need to specify the name of the public NDK library 28 | # you want to add. CMake verifies that the library exists before 29 | # completing its build. 30 | 31 | find_library( # Sets the name of the path variable. 32 | log-lib 33 | 34 | # Specifies the name of the NDK library that 35 | # you want CMake to locate. 36 | log ) 37 | 38 | # Specifies libraries CMake should link to your target library. You 39 | # can link multiple libraries, such as libraries you define in the 40 | # build script, prebuilt third-party libraries, or system libraries. 41 | 42 | target_link_libraries( # Specifies the target library. 43 | HelloNDK 44 | 45 | # Links the target library to the log library 46 | # included in the NDK. 47 | ${log-lib} ) 48 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.1" 6 | defaultConfig { 7 | applicationId "com.zeno.encryptanddecrypt" 8 | minSdkVersion 14 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | externalNativeBuild { 14 | cmake { 15 | // 指定只用clang编译器 16 | // Clang是一个C语言、Objective-C、C++语言的轻量级编译器。 17 | arguments "-DANDROID_TOOLCHAIN=clang" 18 | cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2" 19 | cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2" 20 | // 生成.so库的目标平台 21 | abiFilters "armeabi-v7a" , "armeabi" , "x86" 22 | } 23 | } 24 | } 25 | buildTypes { 26 | release { 27 | minifyEnabled false 28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 29 | } 30 | } 31 | externalNativeBuild { 32 | cmake { 33 | path "CMakeLists.txt" 34 | } 35 | } 36 | } 37 | 38 | dependencies { 39 | compile fileTree(dir: 'libs', include: ['*.jar']) 40 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 41 | exclude group: 'com.android.support', module: 'support-annotations' 42 | }) 43 | compile 'com.android.support:appcompat-v7:24.2.0' 44 | testCompile 'junit:junit:4.12' 45 | } 46 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\android_dev\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/zeno/encryptanddecrypt/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zeno.encryptanddecrypt; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zeno.encryptanddecrypt", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/cpp/HelloNDK.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zeno on 2016/9/10. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //#include "util.h" 11 | 12 | #define LOGE(TAG,FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,TAG,FORMAT,__VA_ARGS__) 13 | 14 | JNIEXPORT jstring JNICALL 15 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_sayHelloNDK(JNIEnv *env, jclass type) { 16 | 17 | // TODO 18 | 19 | return (*env)->NewStringUTF(env, "this String come from C "); 20 | } 21 | 22 | /*加密文件*/ 23 | JNIEXPORT void JNICALL 24 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_fileEncrypt(JNIEnv *env, jclass type, 25 | jstring normalFilePath_, 26 | jstring encryptFilePath_, 27 | jstring password_) { 28 | const char *normalFilePath = (*env)->GetStringUTFChars(env, normalFilePath_, 0); 29 | const char *encryptFilePath = (*env)->GetStringUTFChars(env, encryptFilePath_, 0); 30 | const char *password = (*env)->GetStringUTFChars(env, password_, 0); 31 | 32 | 33 | int passwordLen = strlen(password); 34 | 35 | LOGE("MainActivity","path1 == %s , path2 == %s",normalFilePath , encryptFilePath) ; 36 | 37 | // 读文件指针 38 | FILE* frp = fopen(normalFilePath,"rb") ; 39 | // 写文件指针 40 | FILE* fwp = fopen(encryptFilePath,"wb") ; 41 | 42 | if(frp == NULL) { 43 | LOGE("MainActivity","%s","文件不存在") ; 44 | return; 45 | } 46 | if(fwp == NULL) { 47 | LOGE("MainActivity","%s","没有写权限") ; 48 | } 49 | 50 | // 边读边写边加密 51 | int buffer ; 52 | int index = 0 ; 53 | while((buffer = fgetc(frp)) != EOF) { 54 | 55 | // write 56 | fputc(buffer ^ *(password+(index % passwordLen)),fwp) ; 57 | index++ ; 58 | } 59 | 60 | 61 | // 关闭文件流 62 | fclose(fwp); 63 | fclose(frp); 64 | 65 | LOGE("MainActivity","%s","文件加密成功") ; 66 | 67 | (*env)->ReleaseStringUTFChars(env, normalFilePath_, normalFilePath); 68 | (*env)->ReleaseStringUTFChars(env, encryptFilePath_, encryptFilePath); 69 | (*env)->ReleaseStringUTFChars(env, password_, password); 70 | } 71 | 72 | /*文件解密*/ 73 | JNIEXPORT void JNICALL 74 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_fileDecrypt(JNIEnv *env, jclass type, 75 | jstring encryptFilePath_, 76 | jstring decryptFilePath_, 77 | jstring password_) { 78 | const char *encryptFilePath = (*env)->GetStringUTFChars(env, encryptFilePath_, 0); 79 | const char *decryptFilePath = (*env)->GetStringUTFChars(env, decryptFilePath_, 0); 80 | const char *password = (*env)->GetStringUTFChars(env, password_, 0); 81 | 82 | // 得到密码长度 83 | int passwordLen = strlen(password) ; 84 | 85 | // 读写文件 86 | FILE* encrypt_fp = fopen(encryptFilePath,"rb") ; 87 | FILE* decrypt_fp = fopen(decryptFilePath,"wb"); 88 | 89 | if(encrypt_fp == NULL) { 90 | LOGE("MainActivity","%s","文件不存在,或没有文件读权限"); 91 | return; 92 | } 93 | 94 | if(decrypt_fp == NULL) { 95 | LOGE("MainActivity","%s","没有文件写权限"); 96 | return; 97 | } 98 | 99 | 100 | int buffer ; 101 | int index = 0 ; 102 | 103 | while((buffer = fgetc(encrypt_fp)) != EOF) { 104 | 105 | fputc(buffer ^ *(password+(index % passwordLen)),decrypt_fp); 106 | 107 | index++ ; 108 | } 109 | 110 | // 关闭流 111 | fclose(decrypt_fp) ; 112 | fclose(encrypt_fp); 113 | 114 | LOGE("MainActivity","%s","文件解密成功"); 115 | 116 | (*env)->ReleaseStringUTFChars(env, encryptFilePath_, encryptFilePath); 117 | (*env)->ReleaseStringUTFChars(env, decryptFilePath_, decryptFilePath); 118 | (*env)->ReleaseStringUTFChars(env, password_, password); 119 | } 120 | 121 | /*获取文件大小*/ 122 | long getFileSize(char* filePath) { 123 | 124 | FILE* fp = fopen(filePath,"rb"); 125 | if(fp == NULL) { 126 | LOGE("MainActivity","%s","文件不存在,或没有读文件权限"); 127 | } 128 | fseek(fp,0,SEEK_END); 129 | return ftell(fp); 130 | } 131 | 132 | 133 | 134 | /*文件分割*/ 135 | JNIEXPORT void JNICALL 136 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_fileSplit(JNIEnv *env, jclass type, 137 | jstring splitFilePath_, 138 | jstring suffix_, 139 | jint fileNum) { 140 | const char *splitFilePath = (*env)->GetStringUTFChars(env, splitFilePath_, 0); 141 | const char *suffix = (*env)->GetStringUTFChars(env, suffix_, 0); 142 | 143 | // 要分割文件 , 首先要得到分割文件的路径列表 ,申请动态内存存储路径列表 144 | char** split_path_list = (char**)malloc(sizeof(char*) * fileNum); 145 | 146 | // 得到文件大小 147 | long file_size = getFileSize(splitFilePath); 148 | 149 | // 得到路径字符长度 150 | int file_path_str_len = strlen(splitFilePath); 151 | 152 | // 组合路径 153 | char file_path[file_path_str_len + 5] ; 154 | strcpy(file_path,splitFilePath); 155 | strtok(file_path,"."); 156 | strcat(file_path,"_%d"); 157 | strcat(file_path,suffix); 158 | 159 | int i=0 ; 160 | for (; i < fileNum; ++i) { 161 | 162 | // 申请单个文件的路径动态内存存储 163 | split_path_list[i] = (char*)malloc(sizeof(char) * 128); 164 | // 组合单个路径 165 | sprintf(split_path_list[i],file_path,(i+1)) ; 166 | 167 | LOGE("MainActivity","%s",split_path_list[i]); 168 | } 169 | 170 | 171 | 172 | LOGE("MainActivity","文件大小 == %ld",file_size); 173 | LOGE("MainActivity","文件路径 == %s",splitFilePath); 174 | // 读文件 175 | FILE* fp = fopen(splitFilePath,"rb"); 176 | if(fp == NULL) { 177 | LOGE("MainActivity","%s","文件不存在,或文件不可读"); 178 | return; 179 | } 180 | 181 | // 整除 , 说明各个文件划分大小一致 182 | if (file_size % fileNum) { 183 | // 单个文件大小 184 | int part_file_size = file_size/fileNum ; 185 | LOGE("MainActivity","单个文件大小 == %d",part_file_size); 186 | int i = 0 ; 187 | // 分割多少个文件就分段读多少次 188 | for (; i < fileNum; i++) { 189 | // 写文件 190 | FILE* fwp = fopen(split_path_list[i],"wb"); 191 | if(fwp == NULL) { 192 | LOGE("MainActivity","%s","没有文件写入权限"); 193 | return; 194 | } 195 | int j = 0 ; 196 | // 单个文件有多大 , 就读写多少次 197 | for (; j < part_file_size; j++) { 198 | // 边读边写 199 | fputc(fgetc(fp),fwp) ; 200 | } 201 | 202 | // 关闭文件流 203 | fclose(fwp); 204 | } 205 | } 206 | /*文件大小不整除*/ 207 | else{ 208 | // 不整除 209 | int part_file_size = file_size / (fileNum -1 ) ; 210 | LOGE("MainActivity","单个文件大小 == %d",part_file_size); 211 | int i = 0 ; 212 | for (; i < (fileNum - 1); i++) { 213 | // 写文件 214 | FILE* fwp = fopen(split_path_list[i],"wb"); 215 | 216 | if(fwp == NULL) { 217 | LOGE("MainActivity","%s","没有文件写入权限") ; 218 | return; 219 | } 220 | 221 | int j = 0 ; 222 | for (; j < part_file_size; j++) { 223 | // 边读边写 224 | fputc(fgetc(fp),fwp); 225 | } 226 | 227 | // 关闭流 228 | fclose(fwp); 229 | } 230 | 231 | // 剩余部分 232 | FILE* last_fwp = fopen(split_path_list[fileNum - 1],"wb") ; 233 | i= 0 ; 234 | for (; i < file_size % (fileNum -1); i++) { 235 | fputc(fgetc(fp),last_fwp) ; 236 | } 237 | 238 | // 关闭流 239 | fclose(last_fwp); 240 | 241 | } 242 | 243 | 244 | // 关闭文件流 245 | fclose(fp); 246 | 247 | // 释放动态内存 248 | i= 0 ; 249 | for (; i < fileNum ; i++) { 250 | free(split_path_list[i]) ; 251 | } 252 | 253 | free(split_path_list); 254 | 255 | (*env)->ReleaseStringUTFChars(env, splitFilePath_, splitFilePath); 256 | (*env)->ReleaseStringUTFChars(env, suffix_, suffix); 257 | } 258 | 259 | /*合并文件*/ 260 | JNIEXPORT void JNICALL 261 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_fileMerge(JNIEnv *env, jclass type, 262 | jstring splitFilePath_, 263 | jstring splitSuffix_, 264 | jstring mergeSuffix_, jint fileNum) { 265 | const char *splitFilePath = (*env)->GetStringUTFChars(env, splitFilePath_, 0); 266 | const char *splitSuffix = (*env)->GetStringUTFChars(env, splitSuffix_, 0); 267 | const char *mergeSuffix = (*env)->GetStringUTFChars(env, mergeSuffix_, 0); 268 | 269 | // 1. 申请split文件路径列表动态内存 270 | char** split_path_list = (char**)malloc(sizeof(char*) * fileNum) ; 271 | 272 | 273 | // 2. 组装split文件路径 274 | int split_file_path_len = strlen(splitFilePath) ; 275 | int split_file_path_suffix_len = strlen(splitSuffix); 276 | char split_file_path[split_file_path_len + split_file_path_suffix_len] ; 277 | strcpy(split_file_path,splitFilePath); 278 | strtok(split_file_path,"."); 279 | strcat(split_file_path,"_%d"); 280 | strcat(split_file_path,splitSuffix); 281 | 282 | // 3. 组装merge文件路径 283 | int merge_file_path_len = strlen(mergeSuffix); 284 | char merge_file_path[split_file_path_len + merge_file_path_len] ; 285 | strcpy(merge_file_path,splitFilePath); 286 | strtok(merge_file_path,"."); 287 | strcat(merge_file_path,mergeSuffix); 288 | 289 | LOGE("MainActivity","merge 文件路径 = %s",merge_file_path) ; 290 | 291 | // 4. 循环得到split文件路径列表 292 | int file_path_str_len = strlen(split_file_path); 293 | int i= 0; 294 | for (; i < fileNum; i++) { 295 | split_path_list[i] = (char*)malloc(sizeof(char) * file_path_str_len) ; 296 | 297 | sprintf(split_path_list[i],split_file_path,(i+1)) ; 298 | 299 | LOGE("MainActivity","split文件路径列表 = %s",split_path_list[i]) ; 300 | } 301 | 302 | // 5. 创建并打开 merge file 303 | FILE* merge_fwp = fopen(merge_file_path,"wb") ; 304 | 305 | // 6. 边读边写 , 读多个文件,写入一个文件 306 | i = 0 ; 307 | for (; i < fileNum ; i++) { 308 | 309 | FILE* split_frp = fopen(split_path_list[i],"rb") ; 310 | if(split_frp == NULL) { 311 | LOGE("MainActivity","%s","文件不存在,或没有读文件权限"); 312 | return; 313 | } 314 | long part_split_file_size = getFileSize(split_path_list[i]); 315 | int j = 0 ; 316 | for (; j < part_split_file_size; j++) { 317 | fputc(fgetc(split_frp),merge_fwp); 318 | } 319 | 320 | // 关闭流 321 | fclose(split_frp) ; 322 | 323 | // 每合并一个文件 ,就删除它 324 | remove(split_path_list[i]) ; 325 | } 326 | 327 | // 关闭文件流 328 | fclose(merge_fwp); 329 | 330 | // 释放动态内存 331 | i = 0 ; 332 | for (; i < fileNum; i++) { 333 | free(split_path_list[i]) ; 334 | } 335 | 336 | free(split_path_list); 337 | 338 | LOGE("MainActivity","%s","文件合并完成") ; 339 | 340 | (*env)->ReleaseStringUTFChars(env, splitFilePath_, splitFilePath); 341 | (*env)->ReleaseStringUTFChars(env, splitSuffix_, splitSuffix); 342 | (*env)->ReleaseStringUTFChars(env, mergeSuffix_, mergeSuffix); 343 | } -------------------------------------------------------------------------------- /app/src/main/cpp/util.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feiwodev/EncryptAndDecrypt/bada20ecbf6a6a095e8fea4a205852ce6d05b477/app/src/main/cpp/util.c -------------------------------------------------------------------------------- /app/src/main/cpp/util.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zeno on 2016/9/11. 3 | // 4 | 5 | #ifndef ENCRYPTANDDECRYPT_UTIL_H 6 | #define ENCRYPTANDDECRYPT_UTIL_H 7 | 8 | 9 | #define LOGE(TAG,FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,TAG,FORMAT,__VA_ARGS__) 10 | 11 | 12 | #endif //ENCRYPTANDDECRYPT_UTIL_H 13 | -------------------------------------------------------------------------------- /app/src/main/cpp/utils.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Zeno on 2016/9/10. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/zeno/encryptanddecrypt/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zeno.encryptanddecrypt; 2 | 3 | import android.os.Environment; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.TextView; 9 | 10 | import com.zeno.encryptanddecrypt.ndk.HelloNDK; 11 | 12 | import java.io.File; 13 | 14 | public class MainActivity extends AppCompatActivity { 15 | 16 | private static final String TAG = MainActivity.class.getSimpleName() ; 17 | 18 | // SD_CARD 根路径 19 | private static final String SD_CARD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() ; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_main); 25 | 26 | // Example of a call to a native method 27 | TextView tv = (TextView) findViewById(R.id.sample_text); 28 | tv.setText(HelloNDK.sayHelloNDK()); 29 | 30 | 31 | } 32 | 33 | public void onClick(View view) { 34 | switch (view.getId()) { 35 | 36 | /*文件加密*/ 37 | case R.id.btn_file_encrypt: 38 | fileEncrypt(); 39 | break; 40 | 41 | /*文件解密*/ 42 | case R.id.btn_file_decrypt: 43 | fileDecrypt(); 44 | break; 45 | 46 | /*文件分割*/ 47 | case R.id.btn_file_split: 48 | fileSplit(); 49 | break; 50 | /*文件合并*/ 51 | case R.id.btn_file_merge: 52 | fileMerge(); 53 | break; 54 | } 55 | } 56 | 57 | /*文件加密*/ 58 | private void fileEncrypt() { 59 | String normalFilePath = SD_CARD_PATH+ File.separatorChar+"neck.jpg" ; 60 | String encryptFilePath = SD_CARD_PATH+File.separatorChar+"neck_encrypt.jpg" ; 61 | Log.e(TAG, "fileEncrypt: normalFilePath = "+ normalFilePath + " encryptFilePath = "+encryptFilePath); 62 | 63 | try{ 64 | HelloNDK.fileEncrypt(normalFilePath,encryptFilePath,"xj"); 65 | }catch (Exception e) { 66 | e.printStackTrace(); 67 | } 68 | 69 | } 70 | 71 | /*文件解密*/ 72 | private void fileDecrypt() { 73 | 74 | String encryptFilePath = SD_CARD_PATH+File.separatorChar+"neck_encrypt.jpg" ; 75 | String decryptFilePath = SD_CARD_PATH+File.separatorChar+"neck_decrypt.jpg" ; 76 | 77 | try{ 78 | HelloNDK.fileDecrypt(encryptFilePath,decryptFilePath,"xj"); 79 | }catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | } 83 | 84 | /*分割文件*/ 85 | private void fileSplit() { 86 | String splitFilePath = SD_CARD_PATH+File.separatorChar+"neck.jpg" ; 87 | String suffix = ".b"; 88 | try{ 89 | HelloNDK.fileSplit(splitFilePath,suffix,3); 90 | }catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | 94 | } 95 | 96 | /*文件合并*/ 97 | private void fileMerge() { 98 | String splitFilePath = SD_CARD_PATH+File.separatorChar+"neck.jpg" ; 99 | String splitSuffix = ".b"; 100 | String mergeSuffix = ".jpeg"; 101 | try{ 102 | HelloNDK.fileMerge(splitFilePath,splitSuffix,mergeSuffix,3); 103 | }catch (Exception e) { 104 | e.printStackTrace(); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/zeno/encryptanddecrypt/ndk/HelloNDK.java: -------------------------------------------------------------------------------- 1 | package com.zeno.encryptanddecrypt.ndk; 2 | 3 | /** 4 | * Created by Zeno on 2016/9/10. 5 | * 6 | * NDK Demo 7 | */ 8 | 9 | public class HelloNDK { 10 | 11 | static { 12 | System.loadLibrary("HelloNDK"); 13 | } 14 | 15 | public static native String sayHelloNDK() ; 16 | 17 | /** 18 | * 带密码的文件加密 19 | * @param normalFilePath 要加密的文件路径 20 | * @param encryptFilePath 加密之后的文件路径 21 | * @param password 加密密码 22 | */ 23 | public static native void fileEncrypt(String normalFilePath,String encryptFilePath,String password) ; 24 | 25 | /** 26 | * 带密码的文件解密 27 | * @param encryptFilePath 要解密的文件路径 28 | * @param encryptFilePath 解密之后的文件路径 29 | * @param password 加密密码 30 | */ 31 | public static native void fileDecrypt(String encryptFilePath,String decryptFilePath,String password) ; 32 | 33 | /** 34 | * 文件分割 35 | * @param splitFilePath 要分割文件的路径 36 | * @param suffix 分割文件拓展名 37 | * @param fileNum 分割文件的数量 38 | */ 39 | public static native void fileSplit(String splitFilePath,String suffix,int fileNum); 40 | 41 | /** 42 | * 文件合并 43 | * @param splitFilePath 分割文件的路径 44 | * @param splitSuffix 分割文件拓展名 45 | * @param mergeSuffix 合并文件的拓展名 46 | * @param fileNum 分割文件的数量 47 | */ 48 | public static native void fileMerge(String splitFilePath,String splitSuffix,String mergeSuffix,int fileNum); 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/jni/hellondk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | JNIEXPORT jstring JNICALL 5 | Java_com_zeno_encryptanddecrypt_ndk_HelloNDK_sayHelloNDK(JNIEnv *env, jclass type) { 6 | 7 | // TODO 8 | 9 | 10 | return (*env)->NewStringUTF(env, returnValue); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 |