为APP开发JNI接口以及NDK动态库的时候,需要频繁修改和调试C/C++代码,如果在eclipse或AndroidStudio开发的话,需要1)clean项目,2)ndk build 3)生成APK,启动调试,实际会卸载已安装APK再装一遍,这个过程相当耗时,快则7秒左右,慢则十几秒以上,有没有可能不需要重新安装APK,只需要替换它的so库,重启APP就能自动加载生效?即:

  • 执行ndk-build生成so

  • 替换APP在手机上已安装的so库

  • 重启APP

经过摸索发现可以,整个过程时间缩短为3秒左右。但替换so需要root权限,如果没有root权限怎么办?以下介绍在不需要root权限的环境下实现的方法。

第一步:先将so文件push到sdcard上:

adb push libkplayer.so /sdcard/

第二步:进入shell,并且换APP的身份:

adb shell
run-as com.xxx.jkplayer  #APP包名

这时shell自动切换到/data/data/com.xxx.jkplayer目录下,此目录是可写的,而原来打包在APP里的so库存放在/data/data/com.xxx.jkplayer/lib/下是不可写,所以解决的方法是将修改好的so库copy到/data/data/com.xxx.jkplayer,这需要在JAVA层稍为修改一下加载库的方法:

//System.loadLibrary("jkplayer");
System.load("/data/data/com.xxx.jkplayer/libjkplayer.so");

重新编译和安装APK,这时启动时会提示loadLibrary失败,没关系,做完下一步就可以了。

第三步:从/sdcard上copy过来并赋予可执行权限:

cp /sdcard/libjkplayer.so .  #当前目录在/data/data/com.xxx.jkplayer
chmod 0755 libjkplayer.so 

现在重新启动APP,就可以成功把/data/data/com.xxx.jkplayer/libjkplayer.so load起来,下次我们只需要替换掉这个so,重启APP就可以了,而不需要点AndroidStudio调试按钮了。

我们当然希望写一个脚本来自动实现替换so并重启APP的动作,启动APP:

adb shell am start -n com.xxx.jkplayer/com.xxx.jkplayer.MainActivity

重启之前,可以先强行停止APP:

adb shell am force-stop com.xxx.jkplayer

将这些脚本和ndk-build等组合在一起,每次修改完C/C++代码后,执行脚本,只需要3秒左右APP已经重启就绪。下面我介绍如何为QtCreator IDE配置这些脚本,并且只需要点一个run按钮或ctrl+r就能直接跑起这个脚本,还能显示编译错误和点击定位错误,还能在QtCreator中看到Android的log输出。

为什么使用QtCreator(不需要装QtSDK)?
因为它用来写C/C++代码,轻量级跨平台,代码补全高亮不在话下,书签、代码大纲、编辑器分栏、快捷键都挺好使。 好吧,真正是因为我一直用它,所以觉得顺手。

ndk-build编译错误提示,点击错误跳转到源代码处
ndk-build编译错误提示

ndk-build的编译输出窗口,也可以通过配置将logcat的日志显示到此窗口来。
图片描述

JNI API 自动补全:
图片描述

经常与JNI打资产,如果靠手工查手册就欲哭无泪了-_-~~
也可以配置使得NDK里的库函数和头文件都可以补全,代码阅读时点击跳转。

下面介绍配置过程。

第一步:import jni目录,完成后,保存所有,QtCreator的工程文件也会保存在import目录下
图片描述

第二步:进入项目属性,删除默认的构建步骤(ctrl+b时调用),添加自己的:
图片描述

其中的%{buildDir}\build.bat指的是Qt工程(xxxx.qtcreator)所在目录下的build.bat脚本,内容为:

$NDK\ndk-build -c jni

NDK为指向ndk sdk根目录的环境变量,-c参数指向你jni工程目录,即里面存放c/c++/Android.mk等,如果Qt工程建在jni目录下,-c jni不需要。

clear.bat的内容:

$NDK\ndk-build -c jni clear

第三步:添加自定义的执行步骤(ctrl+r时调用):
图片描述

run.bat:

adb shell am force-stop com.xxx.jkplayer
adb push libs\armeabi-v7a\libjkplayer.so /sdcard/ 
&& adb shell "run-as com.xxx.jkplayer cp -v /sdcard/libjkplayer.so ." 
&& adb shell "run-as com.xxx.jkplayer chmod 0755 libjkplayer.so" 
&& adb shell am start -n com.xxx.jkplayer/com.xxx.jkplayer.MainActivity

executable.bat:

adb shell "logcat -c && logcat -v time | grep -i xxx" #将logcat输出到QtCreator上来

实际使用发现这样打印出来的每行log都被追加了一个空行。当然,你也可以使用AndroidStudio的日志查看器。
OK,现在已经可以用了,编写代码,ctrl+r一下,编译、部署so、重启APP,一步到位。

最后附上代码补全设置:
图片描述
保存后,QtCreator会自动reload,编辑器就立刻高亮JNI和NDK函数,按住ctrl键,将鼠标移到符号上点击就可以跳转,alt+左箭头返回。


jk_v1
1.8k 声望198 粉丝

Linux爱好者,技术积累主要在Linux、Qt、Android,后以Android开发为主,从上层(kotlin,java)到底层(jni,linux)有一定的工作经验和理解,擅长快速学习和知识关联梳理,整合不同技术资源为客户提供合适的解决方案。