安卓开发学习之ndk实现文件的加密解密

背景

这几天在学习Android开发里的ndk开发,今天拿文件的加密解密做为练习。

功能很简单,俩按钮,一个加密一个解密,加密方式就是拿文件的字符跟密钥进行异或,解密方式也是异或


native层

首先动态注册,把java的native方法跟c函数绑定,详情参见文章安卓开发学习之ndk动态注册

以加密为例,我对应的c函数是fileEncrypt(),完整代码如下

jstring fileEncrypt(JNIEnv *env, jclass type, jstring filePath) {
    __android_log_print(ANDROID_LOG_INFO, "native", "进入加密过程");
    fileIndex = 1;

    const char *path = (*env).GetStringUTFChars(filePath, JNI_FALSE);
    const char *newPath = getNewName(path);

    __android_log_print(ANDROID_LOG_INFO, "native", "new file path:%s", newPath);

    FILE *frp = fopen(path, "rb");
    FILE *fwp = fopen(newPath, "wb");

    if (frp == NULL) {
        __android_log_print(ANDROID_LOG_INFO, "native", "%s:此文件不存在或没有读权限", path);
        return NULL;
    }

    if (fwp == NULL) {
        __android_log_print(ANDROID_LOG_INFO, "native", "%s:没有写权限", newPath);
        return NULL;
    }

    int buf;
    int i = 0;

    while ((buf = fgetc(frp)) != EOF) {
        fputc(buf ^ key[i % keyLen], fwp);
        i++;
    }

    fclose(frp);
    fclose(fwp);
    free((void *) path);

    __android_log_print(ANDROID_LOG_INFO, "native", "文件加密结束");
    return env->NewStringUTF(newPath);
}

调用了getName()方法设定新文件的名字,代码如下

char *getNewName(const char *oldName) {
    int len = strlen(oldName);
    char *newName = new char[len + 1];
    int i = 0;

    for (; i < len && oldName[i] != '.'; ++i) {
        newName[i] = oldName[i];
    }

    newName[i] = '1' + fileIndex;
    fileIndex++;

    for (; i < len; ++i) {
        newName[i+1] = oldName[i];
    }

    return newName;
}

而后涉及的密钥信息如下

const char *key = "101010101";
int keyLen = strlen(key);
int fileIndex = 1;

可以看到,所谓的加密就是跟复制粘贴一样的流程化代码,无需赘言


java层

首先在清单文件里声明写外存权限

而后由于Android6.0以后要动态申请权限,所以还要在MainActivity里进行相关操作,代码如下:

public class MainActivity extends Activity {
    public static final String TAG = "MainActivity";
    private Button btn_encrypt, btn_decrypt;
    private String filePath = Environment.getExternalStorageDirectory() + "/new.jpg";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn_encrypt = (Button)findViewById(R.id.btn_encrypt);
        btn_decrypt = (Button)findViewById(R.id.btn_decrypt);

        btn_encrypt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i(TAG, "待加密文件路径:"+filePath);
                if (!TextUtils.isEmpty(filePath) && new File(filePath).exists()) {
                    filePath = FileUtil.fileEncrypt(filePath);
                }
            }
        });

        btn_decrypt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i(TAG, "待解密文件路径:"+filePath);
                if (!TextUtils.isEmpty(filePath) && new File(filePath).exists()) {
                    filePath = FileUtil.fileDecrypt(filePath);
                }
            }
        });

        if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
            btn_decrypt.setClickable(false);
            btn_encrypt.setClickable(false);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == 0) {
            if (checkSelfPermission(permissions[0]) == PackageManager.PERMISSION_GRANTED) {
                btn_decrypt.setClickable(true);
                btn_encrypt.setClickable(true);
            }
        }
    }
}

调用的FileUtil类的代码如下

public class FileUtil {
    static {
        System.loadLibrary("native-lib");
    }

    public static native String fileEncrypt(String filePath);
    public static native String fileDecrypt(String filePath);
}

代码很简单,只是做一下记录


结语和代码地址

网上还有文件的分割和合并的案例,其实本质也是文件的IO,所以此处略过

代码地址:

https://github.com/songzeceng/first/tree/file_encrypt_decrypt

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在进行NDK开发时,Android.mk文件是非常重要的一个文件,它用来描述你的Native代码库的模块依赖关系、编译选项等信息。下面是Android.mk文件编写的一些基本规则和示例。 1. Android.mk文件基本结构 Android.mk文件由一系列的变量定义、模块声明和编译选项等组成。下面是一个基本的Android.mk文件结构: ``` LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := mymodule LOCAL_SRC_FILES := mymodule.c LOCAL_LDLIBS := -llog -landroid include $(BUILD_SHARED_LIBRARY) ``` 其中,`LOCAL_PATH`指定了当前目录路径;`CLEAR_VARS`清除之前的变量定义;`LOCAL_MODULE`指定了模块名称;`LOCAL_SRC_FILES`指定了源代码文件;`LOCAL_LDLIBS`指定了链接库;`BUILD_SHARED_LIBRARY`指定了编译成共享库。 2. 添加多个源文件 如果一个模块由多个源文件组成,可以使用`LOCAL_SRC_FILES`变量指定多个源文件,例如: ``` LOCAL_SRC_FILES := file1.c \ file2.c \ file3.c ``` 3. 添加头文件路径 如果源文件中包含了其他头文件,可以使用`LOCAL_C_INCLUDES`变量指定头文件路径,例如: ``` LOCAL_C_INCLUDES := $(LOCAL_PATH)/include ``` 4. 添加编译选项 如果需要添加编译选项,可以使用`LOCAL_CFLAGS`和`LOCAL_CPPFLAGS`变量,例如: ``` LOCAL_CFLAGS := -Wall -O2 LOCAL_CPPFLAGS := -std=c++11 ``` 5. 添加链接库 如果需要链接其他库,可以使用`LOCAL_LDLIBS`变量,例如: ``` LOCAL_LDLIBS := -llog -landroid ``` 6. 添加静态库 如果需要链接静态库,可以使用`LOCAL_STATIC_LIBRARIES`变量,例如: ``` LOCAL_STATIC_LIBRARIES := libfoo libbar ``` 7. 使用预编译头文件 如果需要使用预编译头文件,可以使用`LOCAL_CXX_FLAGS`变量,例如: ``` LOCAL_CXX_FLAGS += -include myheader.h ``` 8. 模块依赖关系 如果一个模块依赖于另外一个模块,可以使用`LOCAL_STATIC_LIBRARIES`或`LOCAL_SHARED_LIBRARIES`变量来声明依赖关系,例如: ``` include $(CLEAR_VARS) LOCAL_MODULE := libfoo LOCAL_SRC_FILES := foo.c include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libbar LOCAL_SRC_FILES := bar.c LOCAL_STATIC_LIBRARIES := libfoo include $(BUILD_SHARED_LIBRARY) ``` 上面的例子中,模块`libbar`依赖于模块`libfoo`。 以上就是Android.mk文件编写的一些基本规则和示例,希望能够对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值