Android Studio--NDK编译C代码为.so文件,JNI调用
前言:
从Android Studio开始,就支持jni和.so库调用了。
环境:
Windows 7+Android Studio2.1.2+NDK版本:android-ndk-r10e
准备工作:
1) ndk文件:
1,可以根据需求,从网上下载, 网址(科学上网): https://developer.android.com/ndk/downloads/index.html
2,可以查找下当前电脑是否已有ndk包,我的在目录:
C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r10e

2)配置环境变量:
选中System的path变量,进行编辑,把 ;C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r10e添加到最后,保存:



开始:
Step1:新建一个项目




Step2:添加C代码和Android.mk文件
Demo中我们直接使用ndk包自带的C代码做示例,此处我使用hello-jni的代码:

a) 将jni文件夹整体copy,粘贴到main文件夹下:

b)在activity_main.xml中添加一个Button:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="me.jnidemo.myjnidemo.MainActivity"
android:orientation="vertical"> <TextView
android:id="@+id/edv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" /> <Button
android:id="@+id/clickId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="clickBtn"/>
</LinearLayout>
d)新建一个class为NdkJniUtils,在内部声明native方法(jni使用的定义,使用关键字native)
package me.jnidemo.myjnidemo; /**
* Created by c-yangx on 6/22/2016.
*/
public class NdkJniUtils {
static{
System.loadLibrary("hello-jni");//.so文件格式为:lib+库名+.so
}
public static native String stringFromJNI();//函数名与C代码的函数名保持一致
}
c)修改hello-jni.c文件中的函数名称,格式为:Java_包名_类名_函数名( Java_me_jnidemo_myjnidemo_NdkJniUtils_stringFromJNI)

d) jni文件夹 右键=>show in Explorer 进入目录;cmd进入此文件夹中,ndk-build命令进行编译:

此编译会触发gradle,项目中会自动多出libs文件夹:

e)此时在MainActivity.java中添加Button的点击事件:
package me.jnidemo.myjnidemo; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends AppCompatActivity { TextView ev1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); ev1=(TextView)findViewById(R.id.edv) ; Button btn=(Button)findViewById(R.id.clickId);
btn.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View v) {
String res=NdkJniUtils.stringFromJNI();
ev1.setText(res);
}
});
}
}
f) 在gradle.properties中添加配置: android.useDeprecatedNdk=true;
在local.properties中添加 ndk.dir=C\:\\ProgramData\\Microsoft\\AndroidNDK64\\android-ndk-r10e
否则gradle会抛异常
g)运行,触发click事件时,会抛异常:
- ::04.174 -/me.jnidemo.myjnidemo E/AndroidRuntime: FATAL EXCEPTION: main
Process: me.jnidemo.myjnidemo, PID:
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/me.jnidemo.myjnidemo-1/base.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]] couldn't find "libhello-jni.so"
at java.lang.Runtime.loadLibrary(Runtime.java:)
at java.lang.System.loadLibrary(System.java:)
at me.jnidemo.myjnidemo.NdkJniUtils.<clinit>(NdkJniUtils.java:)
at me.jnidemo.myjnidemo.MainActivity$.onClick(MainActivity.java:)
at android.view.View.performClick(View.java:)
at android.view.View$PerformClick.run(View.java:)
at android.os.Handler.handleCallback(Handler.java:)
at android.os.Handler.dispatchMessage(Handler.java:)
at android.os.Looper.loop(Looper.java:)
at android.app.ActivityThread.main(ActivityThread.java:)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:)
因此我们还需进行配置----在build.gradle中做一个资源路径指定即可:
// build.gradle
android {
//
//...
sourceSets {
main {
//你的源码目录
jniLibs.srcDirs 'src/main/libs'
}
}
}
重新编译运行,ok了:

补录:
a)指定生成基于哪些CPU架构的.so文件:
1) Application.mk文件配置方式:
本文配置项,生成的为全架构平台的.so文件,缺点是会使得apk包变大:

可以修改,指定多个平台。如: APP_ABI := armeabi armeabi-v7a x86 mips
b)build.gradle配置方式:在app module目录下的build.gradle中设置库文件名(生成的so文件名),找到gradle文件的defaultConfig这项,在里面添加如下内容:
defaultConfig {
......
ndk{
//moduleName "YanboberJniLibName" //生成的so名字
abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库。目前可有可无。
}
}
b) Android.mk配置含义:
LOCAL_PATH := $(call my-dir) #提定当前路径 include $(CLEAR_VARS) #清除全局配置变量,LOCAL_XXX,除了LOCAL_PATH LOCAL_MODULE := hello #指定生成动态库名hello,生成的动态库文件libhello.so
LOCAL_SRC_FILES := hello.c #指定生成动态库的源文件 include $(BUILD_SHARED_LIBRARY) #提定生成动态库
后续:
a) Bug 1 => app:compileDebugNdk FAILED

最近在研究WebRtc的APM(Audio_Processing_Module)音频处理模块,将所有的C代码文件导入项目,通过ndk-build命令在cmd窗口编译时,一切ok。
但是项目编译时却报此错误,最后(科学上网)找到了解决方案(网址:http://stackoverflow.com/questions/27453085/execution-failed-for-task-appcompiledebugndk-failed-to-run-this-command-ndk),

大体意思就是说gradle尝试自己编译你的源文件,而不是使用你编译好的.so文件。既然在cmd中编译通过了,那么咱们可以通过配置,禁用gradle的ndk调用行为
,而使用你配置的路径下的.so文件。于是,我在app build.gradle中添加了 => jni.srcDirs = [],然后编译运行,一切ok了。

Android Studio--NDK编译C代码为.so文件,JNI调用的更多相关文章
- Android studio NDK 编译 "$USE_DEPRECATED_NDK=true" 异常问题解决
我的项目是https://github.com/leixiaohua1020/simplest_ffmpeg_mobile/tree/master/simplest_ffmpeg_android_st ...
- Android Studio NDK 学习之接受Java传入的字符串
本博客是基于Android Studio 1.3 preview版本,且默认你已经安装了Android SDK, Android NDK. 用Android Studio新建一个工程叫Prompt,其 ...
- Android Studio NDK环境配置
本文参考:Android Studio NDK环境配置及JNI使用方法:http://blog.csdn.net/tongseng/article/details/53005123 并添加自己的实践: ...
- Android Studio NDK编程初探
继上一篇学习了如何使用NDK编译FFMPEG后,接下来就是要学习如何在Android Studio中使用了. 经过参考和一系列的摸索,记录下具体步骤. 创建C++ Support的Android St ...
- Android studio 加速编译方法
JRebel for Android 是一个Android Studio的插件,可以大大加速Android Studio的编译速度,对于小项目来说或许不明显:但是当项目达到一定的规模时,它对于Andr ...
- 【Android】Android Studio NDK 开发
Android Studio NDK 开发 记录在Android Studio中NDK简单开发的步骤 用到的Android Studio版本为3.5. 配置NDK 下载NDK 一般在SDK下已经有自带 ...
- Android 使用NDK编译二进制文件并运行
Android 使用NDK编译二进制文件并运行本文介绍如何编译可以在Android平台上运行的二进制可执行文件. 首先我们,知道,Android是基于Linux的,而在Linux上,可以执行二进制文件 ...
- 使用Android Studio向GitHub提交代码
使用Android Studio向GitHub提交代码 在GitHub上创建一个仓库 填写仓库名称.描述.类型(公有.私有)等信息,点击创建 到此,成功创建了我们的仓库,并且初始化创建了README. ...
- 加快Android Studio的编译速度
从Eclipse切换到Android Studio后,感觉Android Studio的build速度比Eclipse慢很多,以下几个方法可以提高Android Studio的编译速度 使用Gradl ...
随机推荐
- OpenDigg - 挖掘优质开源项目库
OpenDigg - 挖掘优质开源项目库 OpenDigg专注于挖掘优质的开源项目库,通过技术和人工将软件项目分类整理,同时辅助简要的编译,方便广大程序员便捷地找到需要的开源项目. OpenDigg刚 ...
- python 操作solr索引数据
测试代码1: def test(self): data = {", "*字段名*": u"我是一个大好人"}}} params = {"bo ...
- mac更新系统后Git不能用,提示missing xcrun at
今天更新了mac系统,然后就踩了这个坑. 启动AndroidStudio 右上角提示: can't start git: /usr/bin/git probably the path to git e ...
- Android实现批量照片上传至server,拍照或者从相冊选择
近期因为项目需求,须要完毕批量照片上传,折腾了一段时间,最终完毕了,达到了例如以下效果 主界面主要有GridView组成和button组成,当按下一个格点时,会调用相机或者相冊,拍照或者选择相冊照片, ...
- 集成方法:渐进梯度回归树GBRT(迭代决策树)
http://blog.csdn.net/pipisorry/article/details/60776803 单决策树C4.5由于功能太简单.而且非常easy出现过拟合的现象.于是引申出了很多变种决 ...
- UVALive 3971 Assemble(模拟 + 二分)
UVALive 3971 题意:有b块钱.想要组装一台电脑,给出n个配件的种类,名字,价格,品质因子.若各种类配件各买一个,总价格<=b,求最差品质配件的最大品质因子. 思路: 求最大的最小值一 ...
- SEO优化100条
1.准备个好域名.①.尽量在5位数内,当然也不一定,反正要让用户好记.(看个人):②.尽量用顶级的域名,搜索排名感觉好一点.③.做中文站最好用拼音注册,不要问为什么.看百度(baidu.com)就是很 ...
- vue 预渲染 prerender-spa-plugin
1.预渲染说明 https://ssr.vuejs.org/zh/#为什么使用服务器端渲染-ssr-? 如果你调研服务器端渲染(SSR)只是用来改善少数营销页面(例如 /, /about, /cont ...
- 提高PAAS安全性的一点尝试
云服务已经成为现代人生活的一部分.手机中的照片会自己主动同步到云中:你的邮件内容保存在云中.办公软件执行在云中:你的健康数据会实时上传到云中.你每天的生活轨迹消耗的卡路里也会上传到云中:云服务也会逐渐 ...
- Jenkins spring boot 自动部署方案
原文地址:http://www.cnblogs.com/skyblog/p/5632869.html 现在主流的自动部署方案大都是基于Docker的了,但传统的自动部署方案比较适合中小型公司,下面的方 ...