├── .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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
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 | 
15 |
16 | 就几个按钮 , 布局文件就不贴代码了 , 读者也可以整个输入框,可以输入加密的密码 。
17 |
18 |
19 | 
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 | 
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 | 
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 |
24 |
25 |
32 |
33 |
40 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiwodev/EncryptAndDecrypt/bada20ecbf6a6a095e8fea4a205852ce6d05b477/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiwodev/EncryptAndDecrypt/bada20ecbf6a6a095e8fea4a205852ce6d05b477/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiwodev/EncryptAndDecrypt/bada20ecbf6a6a095e8fea4a205852ce6d05b477/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiwodev/EncryptAndDecrypt/bada20ecbf6a6a095e8fea4a205852ce6d05b477/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiwodev/EncryptAndDecrypt/bada20ecbf6a6a095e8fea4a205852ce6d05b477/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | EncryptAndDecrypt
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/zeno/encryptanddecrypt/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.zeno.encryptanddecrypt;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.0-rc2'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/feiwodev/EncryptAndDecrypt/bada20ecbf6a6a095e8fea4a205852ce6d05b477/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------