Android使用已有so库自己实现jni封装
2016-11-30 21:07
453 查看
为什么写这个
最近项目需要在盒子上实现内容的加解密,方案是使用机顶盒内部主芯片加解密算法对存储在内容分区的资源进行加密,然后由机顶盒平台提供本地库的方式给应用使用。所以也就有了这个事情。一般情况下,完全可以由C层代码直接实现和封装JNI本地接口然后打成so文件,然后提供给应用开发者使用。今天要说的情况基于这样的场景:
底层代码实现者已经将C代码编译成so库,然后直接提供给上层开发者使用,这样他们便无需考虑适配不同上层使用者的具体接口。更可能是,别人只负责把本地代码实现了,然后提供一个so,具体封装由上层开发者自己完成的场景。
怎么做
首先,我们需要有知道两个:①库文件so,
②库中自己需要调用的功能函数。
这里我的库文件是libminzip.so; 调用的接口函数如下:
bool extractZip(const char* zipFile, const char* destPath, bool zipCurrentPath, bool crypt)
这个函数实现了文件解压的功能。知道这些,那么我们就可以依据这个来进行封装接口然后提供给app调用了。
这里我使用Eclipse+NDK的方式来做:
代码目录如下:
step1
可以在项目目录下新建jni目录,把我们已经有的libminzip.so文件放到prebuilt目录下。step2
在preduilt目录下创建Android.mk文件:LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := minzip LOCAL_SRC_FILES := libminzip.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) include $(PREBUILT_SHARED_LIBRARY)
step3
在java代码中创建本地接口类:package com.tfxiaozi.contentupdater.jni; /** * Created by dongqiang 2016/11/18. */ public class UnZipAndEncrypt { static { System.loadLibrary("minzip"); System.loadLibrary("unzipandencrypt"); } private native boolean unzipAndEncypt(String srcPath, String destPath, boolean zipCurrentPath, boolean isCrypted); public static void onUnzipProcess(String fileName, float progress) { } }
step4
编写jni文件#include <jni.h> #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdbool.h> #include <android/log.h> #define LOG_TAG "UNZIP_AND_ENCRYPT" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) char* Jstring2CStr(JNIEnv* env, jstring jstr) { char* rtn = NULL; jclass clsstring = (*env)->FindClass(env, "java/lang/String"); jstring strencode = (*env)->NewStringUTF(env, "UTF-8"); jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); jsize alen = (*env)->GetArrayLength(env, barr); jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE); if(alen > 0) { rtn = (char*)malloc(alen+1); //"\0" memcpy(rtn, ba, alen); rtn[alen]=0; } (*env)->ReleaseByteArrayElements(env, barr, ba, 0); return rtn; } jboolean native_unzip_and_encrypt(JNIEnv *env, jobject jobj, jstring zipFile, jstring destPath, jboolean unzipCurrentPath, jboolean isCrypted) { const char* czipFile = (const char*)Jstring2CStr(env, zipFile); const char* cdestPath = (const char*)Jstring2CStr(env, destPath); return extractZip(czipFile, cdestPath, unzipCurrentPath, isCrypted); } static JNINativeMethod gMethods[] = { {"unzipAndEncypt", "(Ljava/lang/String;Ljava/lang/String;ZZ)Z", (void*) native_unzip_and_encrypt} }; static const char* const gClassUnZipAndEncrypt = "com/tfxiaozi/contentupdater/jni/UnZipAndEncrypt"; //注册native方法到java中 static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = (*env)->FindClass(env, className); if (clazz == NULL) { return JNI_FALSE; } if ((*env)->RegisterNatives(env, clazz, gMethods,numMethods) < 0){ return JNI_FALSE; } return JNI_TRUE; } static int register_unZipAndEncrypt(JNIEnv* env) { return registerNativeMethods(env, gClassUnZipAndEncrypt, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); } jint JNI_OnLoad(JavaVM *vm,void *reserved){ JNIEnv *env=NULL; jint result=-1; if((*vm)->GetEnv(vm,(void**)&env,JNI_VERSION_1_4)!=JNI_OK){ return -1; } assert(env !=NULL); if(register_unZipAndEncrypt(env)<0){ return -1; } return JNI_VERSION_1_4; }
step5
编写jni目录下的Android.mk文件LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES :=libminzip LOCAL_MODULE := unzipandencrypt LOCAL_SRC_FILES := unzip_and_encrypt.c LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY) include $(LOCAL_PATH)/prebuilt/Android.mk
编译
前面说了,使用的ndk,那么需要配置Ndk目录到系统环境变量中,这里就不赘述了。上个图吧:编译通过,可以在项目目录中看到生成的文件:
把这两个so加入到工程的lib目录下就可以使用了,接口已经在前面的java代码中定义,需要同时加载两个库文件:
System.loadLibrary(“minzip”);
System.loadLibrary(“unzipandencrypt”);
细心的小伙伴会发现上面的jni代码有字符串没有释放资源。
OK,到这里就结束了~~~
相关文章推荐
- Android使用自己封装的Http和Thread、Handler实现异步任务
- vlc-android 中调用用libvlcjni.so实现流媒体播放,自己使用libvlcjni.so
- Delphi使用android的NDK是通过JNI接口,封装好了,不用自己写本地代码,直接调用
- Android使用JNI实现Java与C之间传递数据 .
- Android使用JNI实现Java与C之间传递数据
- 在android中使用xml调用webservice,实现自己的单词查询
- Ubuntu上使用android4.0.3模拟器实现JNI例子
- Android使用JNI实现Java与C之间传递数据
- Android使用JNI实现Java与C之间传递数据
- 初学Android,使用ContentResolver获取自己实现的ContentProvider的数据(五十六)
- Android-使用单例模式实现自己的HttpClient工具类
- Android使用JNI实现Java与C之间传递数据
- Android使用JNI实现Java与C之间传递数据
- Android使用JNI实现Java与C之间传递数据
- Android使用JNI实现Java与C之间传递数据
- Android jni调用,实现自己的JNI_OnLoad函数
- Android使用JNI实现Java与C之间传递数据
- Ubuntu上使用android4.0.3模拟器实现JNI例子
- Android使用Jni实现压力锅数据检测效果示例
- Android 号码, 来电归属地 Jni 使用C++对二进制文件查询(二) C++实现篇