你好,我现在能够用NDK的如下方式写几个简单的文件,然后打包为SO,再用另外的一个.C文件调用SO,然后生成最终的供Android使用的SO文件,具体方式如下:
下载一个从android模拟器里取system lib的工具busybox,然后调用命令
$adb push busybox /dev/sample/busybox
$adb shell chmod 777 /dev/sample/busybox
$adb shell ./dev/sample/busybox tar -cf /dev/sample/libs.tar /system/lib
$adb pull /dev/sample/libs.tar libs.tar
这样就将模拟器下的 /system/lib 目录的所有库(so)文件打包并下载下来了,解压libs.tar就得到了我们所需要的所有库文件。
接着将所有的文件 到 $(NDK)\build\prebuilt\windows\arm-eabi-4.2.1\lib\gcc\arm-eabi\4.2.1,这个时候基本的配置工作就结束了。
然后建立tutorial01.c调用tutorial02.c中的方法,通过写makefile文件将之打包为SO
CC = /cygdrive/e/android-ndk-1.5_r1/build/prebuilt/windows/arm-eabi-4.2.1/bin/arm-eabi-gcc
CFLAGS = -g -O2 -fPIC -DANDROID -I ./ -I ../ -I /cygdrive/e/android-ndk-1.5_r1/build/platforms/android-1.5/arch-arm/usr/include
SDFLAGS = -nostdlib -Wl,-T,armelf.xsc -Wl,-soname,$@ -Wl,-shared,-Bsymbolic -lc
CRT_OBJS= -lz -lm
# source files:
SRCS= tutorial01.c tutorial02.c tutorial02.h
all: libtutorial.so
libtutorial.so: tutorial01.o tutorial02.o
$(CC) $(SDFLAGS) -o $@ tutorial01.o tutorial02.o $(CRT_OBJS)
tutorial01.o: tutorial02.h
tutorial02.o: tutorial02.h
clean:
rm -f libtutorial.so *.o
然后make,这个时候会报错 can't find "armelf.xsc", 在ndk的目录里搜索一下,搜到之后 到$(NDK)\build\prebuilt\windows\arm-eabi-4.2.1\lib\gcc\arm-eabi\4.2.1,然后make,成功。
接着建立一个文件test01.c,动态加载so文件,然后写一个makefile文件,最后make成功。
建立一个Android工程 testapp来测试其运行情况,实验表明是能够正确运行的。
⑵ 如何动态加载android的so文件,如何压缩apk尺寸,androidapk
在Android中调用动态库文件(*.so)都是通过jni的方式,而且往往在apk或jar包中调用so文件时,都要将对应so文件打包进apk或jar包,工程目录下图:
以上方式的存在的问题:
1、缺少灵活性比较类似静态加载了(不是静态加载),能加载的so文件绑定死了;
2、但so文件很多或很大时,会导致对应的apk和jar包很大;
3、不能动态的对so文件更新;
Android中加载so文件的提供的API:
void System.load(String pathName);
说明:
1、pathName:文件名+文件路劲;
2、该方法调用成功后so文件中的导出函数都将插入的系统提供的一个映射表(类型Map);
看到以上对System.load(String pathName);的函数说明可定有人会想到将so文件放到一个指定的目录然后再通过参数pathName直接引用该目录的路劲和对应的so文件问题不就解决了吗?
这里有个问题被忽略了,那就是System.load只能加载两个目录路劲下的so文件:
1、/system/lib ;
2、安装包的路劲,即:/data/data/<packagename>/…
而且这两个路劲又是有权限保护的不能直接访问;
问题解决方法:
先从网络下载so文件到手机目录(如:/test/device/test.so) –> 将test.so加载到内存(ByteArrayOutputStream) –> 然后保存到对用安装包目录;
具体代码如下:
try {
String localPath = Environment.getExternalStorageDirectory() + path;
Log.v(TAG, "LazyBandingLib localPath:" + localPath);
String[] tokens = mPatterns.split(path);
if (null == tokens || tokens.length <= 0
|| tokens[tokens.length - 1] == "") {
Log.v(TAG, "非法的文件路径!");
return -3;
}
// 开辟一个输入流
File inFile = new File(localPath);
// 判断需加载的文件是否存在
if (!inFile.exists()) {
// 下载远程驱动文件
Log.v(TAG, inFile.getAbsolutePath() + " is not fond!");
return 1;
}
FileInputStream fis = new FileInputStream(inFile);
File dir = context.getDir("libs", Context.MODE_PRIVATE);
// 获取驱动文件输出流
File soFile = new File(dir, tokens[tokens.length - 1]);
if (!soFile.exists()) {
Log.v(TAG, "### " + soFile.getAbsolutePath() + " is not exists");
FileOutputStream fos = new FileOutputStream(soFile);
Log.v(TAG, "FileOutputStream:" + fos.toString() + ",tokens:"
+ tokens[tokens.length - 1]);
// 字节数组输出流,写入到内存中(ram)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = fis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
// 从内存到写入到具体文件
fos.write(baos.toByteArray());
// 关闭文件流
baos.close();
fos.close();
}
fis.close();
Log.v(TAG, "### System.load start");
// 加载外设驱动
System.load(soFile.getAbsolutePath());
Log.v(TAG, "### System.load End");
return 0;
} catch (Exception e) {
Log.v(TAG, "Exception " + e.getMessage());
e.printStackTrace();
return -1;
}
⑶ 如何获取android 系统的so库
android ndk调用第三方的so库文件的步骤如下:
1.将SO文件直接放到libs/armeabi下,然后代码中System.loadLibrary("xxx");再public native static int xxx_xxx_xxx();接下来就可以直接调用xxx_xxx_xxx()方法;
2.第二种方案,创建自己的SO文件,在自己的SO文件里调用第三方SO,再在程序中调用自己的SO,这种比较复杂,需要建java类文件,生成.h文件,编写C源文件include之前生成的.h文件并实现相应方法,最后用android NDK开发包中的ndk-build脚本生成对应的.so共享库;
⑷ 如何动态加载android的so文件,如何压缩apk尺寸
您好,很高兴为您解答。
一、 工具集介绍 (项目地址: https://github.com/liyuming1978/NativeLibCompression)
安卓压缩工具集提供了一个极为简洁的方法,能够比安卓原有的Zip提供更高压缩比的存储应用内的so文件 (后期版本还可以支持压缩动态加载的jar包,以及游戏资源文件),同时提供了应用内网络更新下载压缩文件的方法,使得应用可以将部分so存储到云端,减小应用的尺寸。
压缩原理: 压缩工具会把所有的so使用LZMA算法压缩到assert目录,应用在第一次启动的时候,会解压到应用的私有目录下
二、 工具集组成
工具集为一个安装程序,建议安装在默认路径下,安装在program files下在win7可能有读写权限的问题导致一些异常
安装后,你可以看见4个目录,此目录内都含有源码。
安装后的四个目录如下
其中 ApkLibComrepss 为java命令行程序的源码,在此目录的bin子目录中,你可以找到ApkCompress.jar ,使用这个文件可以把一个普通的apk文件转换为压缩的apk文件
CompressDemo为一个样例代码,你可以参考这个代码知道如何整合压缩的SDK。
DecRawso是压缩的SDK,你的开发工程需要引用这个SDK,并进行一些源码上的修改,才能整合压缩的功能
RawsoCreator为windows下的转换工具, 这个工具一般无需使用, 仅仅在调试和二次开发压缩SDK的时候使用。
三、 如何整合压缩SDK
打开CompressDemo,我们以这个工程为例子讲解如何整合压缩SDK
1. 首先需要引入DecRawso工程
2. 然后需要在你的工程内最初始的地方调用DecRawso.NewInstance。在此demo工程内,是在MainActivity.java的OnCreate内调用了此方法, 此方法是创建了一个解压的唯一实例。注意:此方法是异步的,所以你可以传入一个handler接受异步解码完成的消息,如果同时传入参数showProgress=true,SDK内会产生一个进度对话框以阻塞主进程。不推荐使用DecRawso.NewInstance(mContext,null,false);的方式,此方式不接受任何消息,且无进度对话框,解压会在后台自动完成,并且在应用第一次load so的时候阻塞直到后台解压完成。所以如果阻塞时间过长,可能会导致应用无响应。
3. 修改load so文件的方法:所有的System.loadlibrary(***)改为 System.load(DecRawso.GetInstance().GetPath(“***"));
新版本, 这步可以省略了,sdk会修改system的libaray加载路径,一般情况下,系统升级不会出问题 (非正规代码,小概率会随android升级修改新的代码),如果方便的话,还是采用System.load(DecRawso.GetInstance().GetPath(“***"))
经过这几个简单的步骤,压缩的SDK已经整合到工程内了。
四、 如何压缩发布APK
使用ApkCompress.jar压缩发布APK。 此工具为命令行工具。一般的此命令使用方式为:在命令行运行ComPressApk.jar-a C:/my/test.apk -k c:/key *** ### alias -x86http://www.test.com (也可以运行 java –jarComPressApk.jar )
-a 后面跟apk路径名, 可以不是全路径
-k 后面是签名文件[key storepasskeypass alias name] ,key可以不是全路径名 (name 如果不写, 默认就是CERT)
-x86 表示需要存储x86库文件在云端, 后面跟以http://开头的链接,最后实际的存储位置应该为 http://www.test.com/cloudrawso_x86
命令执行完以后, 会生成test_CompressAlign.apk. 这个apk就是压缩后的apk
五、 开发模式和压缩模式
为了方便开发,在实现开发的过程中(修改了源码支持压缩后),也可以不压缩so,apk也可以正常运行,压缩的SDK内部会自动判断是否有压缩包, 如果没有压缩包,则加载的路径恢复成android默认的路径。所以最方便的开发是,先整合代码,在开发过程中和原来一样开发(不压缩),在发布的时候才压缩apk
六、 X86和ARM库混合调用
在实现开发过程中,可能会有某些第三方库确实没有x86版本,通常情况下ISV并不在x86目录下放置arm的第三方库,那么在实际运行过程中会导致缺库现象的发生。在缺库的情况下,压缩的SDK会在x86设备上自动解压arm的压缩包,避免缺库现象的发生。(只有真正加载了缺失的库才是缺库,库文件不一致并不一定就是缺库)
但是显然这样会导致运行的低效率,如果在第三方so和x86的库完全没有相互引用的情况下(也就是说这些库都是java层使用JNI调用的,在native层没有相互调用),可以拷贝arm的第三方库到x86目录下,这样就不会出现缺库的情况。当然这种情况会导致arm库多余的拷贝,在以前的zip压缩情况下,会使得压缩包变大,但是在新的LZMA压缩情况下,库大小完全不会增大,因为LZMA压缩由于字典比较大,能够尽可能的压缩关联的几个文件,如果文件完全相同,LZMA的压缩会和单个文件基本一致。
如若满意,请点击右侧【采纳答案】,如若还有问题,请点击【追问】
希望我的回答对您有所帮助,望采纳!
~ O(∩_∩)O~
⑸ AndroidStudio如何配置NDK/JNIAndroidStudio怎么调用so动态链接库
AndroidStudio怎么调用so动态链接库?在我们日常开发中,经常会用到一些复杂的加密的算法以保证通信的安全。通常这些算法会用C或C++实现后打包成.so动态链接库并向Java层开发接口方便调用。
以AndroidStudio为例
1 . 首先去下载NDK包,下载路径如下可根据自己系统定点下载
https://developer.android.google.cn/ndk/downloads/index.html
static{
System.loadLibrary("jnitext");
}
publicnativeStringget_1111CLang_1String();