注:首发地址

上周,写了个小demo,正好同事使用的小米手机系统内核更新到7.0,遂拿来测试了一番。其中遇到的小问题,现在来跟大家分享一下。友情提示:我在解决问题的过程中,看了很多博客,这其中内容详实,排版简洁的要推一下亦枫,他的主页:

之前已经用自定义View做出如下这样一个效果了

0. 前言

如果只学理论,不做实践,不踩踩坑,一般很难发现真正实践项目中的问题的,也比较难以加深对技术的理解。所以延续上篇
JNI 的实战Android NDK开发:JNI实战篇 ,这篇主要是一些 NDK
小项目的练习,由于这些项目网上都有
demo介绍,这里不会具体一步步介绍如何操作,只记录一些个人需要注意的地方或一些主要步骤,详细的介绍或代码可以点击里面的链接查看。

问题点描述:

自动更新功能,下载更新的apk文件后,跳转到系统的应用程序安装界面进行安装,这里传入的Uri.fromFile(“apkFile”)的格式,默认得到的是
file:// 类型的 URI。

图片 1这里写图片描述

1. 文件加解密和分割合并

所有文件都是二进制存储的,无论是文本,图片还是视频文件都是以二进制存储在磁盘中。所以可以通过对文件进行二进制运算进行加解密。下面用到的是比较简单的^异或运算来对文件加解密(算是一种对称加密算法)附:加解密算法扩展:加解密算法
· 区块链技术指南

一般在大文件传输时,如音视频文件,会将文件分割后再传输,从而提高效率。当需要使用时,再将分割后的文件合并即可。

而文件加解密设计到安全,可以使用 NDK
增加反编译的难度。另外文件的分割合并都比较耗性能,可以放到 NDK
处理提高效率。

以下练习参考:NDK开发基础②文件加密解密与分割合并 – 简书

效果图如图,进入界面会拷贝两张 assets
的图片cats.jpgimage.jpg到本地 sdcard/NdkSample
目录下作为测试。加密后的图片
cats_encypt.jpg是无法直接查看的,合成的图片是 image.jpeg

图片 2效果图

Java 代码

public class FileUtils { private static final String FILE_PATH_PREFIX = Environment.getExternalStorageDirectory() + File.separator; private static final String FOLDER_NAME = "NdkSample" + File.separator; public static final String FILE_PATH = FILE_PATH_PREFIX + FOLDER_NAME; public static boolean fileEncrypt() { String normalFilePath = FILE_PATH + "cats.jpg"; String encryptFilePath = FILE_PATH + "cats_encrypt.jpg"; try { return fileEncrypt(normalFilePath, encryptFilePath); } catch (Exception e) { e.printStackTrace(); } return false; } public static boolean fileDecode() { String encryptFilePath = FILE_PATH + "cats_encrypt.jpg"; String decodeFilePath = FILE_PATH + "cats_decode.jpg"; try { return fileDecode(encryptFilePath, decodeFilePath); } catch (Exception e) { e.printStackTrace(); } return false; } private static native boolean fileEncrypt(String normalFilePath, String encryptFilePath); private static native boolean fileDecode(String encryptFilePath, String decodeFilePath);}

JNI 加密代码实现,注意加文件读写权限

const char *PASSWORD = "pw";long getFileSize(char* filePath);extern "C"JNIEXPORT jboolean JNICALLJava_cn_cfanr_ndksample_utils_FileUtils_fileEncrypt(JNIEnv *env, jclass type, jstring normalFilePath_, jstring encryptFilePath_) { const char *normalFilePath = env->GetStringUTFChars(normalFilePath_, 0); const char *encryptFilePath = env->GetStringUTFChars(encryptFilePath_, 0); int passwordLen = strlen; LOGE("要加密的文件的路径 = %s , 加密后的文件的路径 = %s", normalFilePath, encryptFilePath); //读文件指针 FILE *frp = fopen(normalFilePath, "rb"); // 写文件指针 FILE *fwp = fopen(encryptFilePath, "wb"); if (frp == NULL) { LOGE; return JNI_FALSE; } if (fwp == NULL) { LOGE; return JNI_FALSE; } // 边读边写边加密 int buffer; int index = 0; while ((buffer = fgetc != EOF) { // write fputc(buffer ^ *(PASSWORD + (index % passwordLen)), fwp); //异或的方式加密 index++; } // 关闭文件流 fclose; fclose; LOGE; env->ReleaseStringUTFChars(normalFilePath_, normalFilePath); env->ReleaseStringUTFChars(encryptFilePath_, encryptFilePath); return JNI_TRUE;}

解密代码类似。

Java 代码实现

public static boolean fileSplit() { String splitFilePath = FILE_PATH + "image.jpg"; String suffix = ".b"; try { return fileSplit(splitFilePath, suffix, 4); } catch (Exception e) { e.printStackTrace(); } return false; } /** * 文件合并 * * @return */ public static boolean fileMerge() { String splitFilePath = FILE_PATH + "image.jpg"; String splitSuffix = ".b"; String mergeSuffix = ".jpeg"; try { return fileMerge(splitFilePath, splitSuffix, mergeSuffix, 4); } catch (Exception e) { e.printStackTrace(); } return false; } /** * 文件分割 * * @param splitFilePath 要分割文件的路径 * @param suffix 分割文件的扩展名 * @param fileNum 分割文件的数量 * @return */ private static native boolean fileSplit(String splitFilePath, String suffix, int fileNum); /** * 文件合并 * * @param splitFilePath 分割文件的路径 * @param splitSuffix 分割文件的扩展名 * @param mergeSuffix 合并文件的扩展名 * @param fileNum 分割文件的数量 * @return */ private static native boolean fileMerge(String splitFilePath, String splitSuffix, String mergeSuffix, int fileNum);

注意,文件的分割合并需要设置文件扩展名后分割文件数量。分割时,分两种情况,1)能整除的,直接平均分;2)不能整除的,fileSize
% ,前 n -1
个平均分,剩余的留给最后一个;合并时,需要注意的是,必须按照分割的顺序合并

其余 JNI 实现代码略,可以到 GitHub
查看具体源码:NdkSample/native_file_handler.cpp

写在前面的话

由于 Android 7.0 或更高版本的系统在国内手机市场上的占比不是很高,很多
Android 开发人员并没有做 7.0
适配工作,同时测试人员也容易忽视这方面的兼容问题。这导致 7.0
及以上版本的手机用户在使用到应用部分功能时可能出现 App
崩溃闪退。其中,大部分原因都是由项目中使用到 file:// 类型的 URI
所引发的。

这两天需要重新拿来使用,发现效果虽然做出来了,不过思路不太对,就重新参考写了一个,用法也更为简单了

发表评论

电子邮件地址不会被公开。 必填项已用*标注