最后
这里我希望可以帮助到大家提升进阶。
内容包含:Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。
喜欢本文的话,不妨给我点个小赞、评论区留言或者转发支持一下呗~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
和配置 Java JDK 环境变量相同,不会的可以自行百度,配置 NDK 环境变量有很多种方式;
三、在自己项目创建本地方法:
即:在 Java 类中创建带有 native 的方法;
项目或者应用的包名:com.ang.ndkdemo
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//创建的本地方法,具体功能在C或者C++中实现
public native String fromJNIString();
}
四、手动创建本地方法 fromJNIString() 对应的. h 头文件
1,在电脑的 cmd 或者 AndroidStudio 的 Terminal 中输入 javah -d D:\Demo\NDKDemo\app\src\main\jni -classpath D:\Demo\NDKDemo\app\src\main\java com.ang.ndkdemo.MainActivity
javah -d D:\Demo\NDKDemo\app\src\main\jni -classpath D:\Demo\NDKDemo\app\src\main\java
com.ang.ndkdemo.MainActivity
- a, -d D:\Demo\NDKDemo\app\src\main\jni 创建 jni 文件夹并指定. h 输出目录
- b, D:\Demo\NDKDemo\app\src\main\jni 要创建的. h 头文件输出的绝对路径
- c, D:\Demo\NDKDemo\app\src\main\java com.ang.ndkdemo.MainActivity 包含本地方法 (fromJNIString()) 的类路径;注意不要写成了 D:\Demo\NDKDemo\app\src\main\java\com\ang\ndkdemo\MainActivity(把包名中的点 “.” 写成了斜杠 “****”,这样写是不对的) **;**com.ang.ndkdemo.MainActivity(注意是包名 + 类名);
- 参数说明
-classpath :类搜索路径,这里表示从当前的 D:\Demo\NDKDemo\app\src\main\java 目录下查找
-d :将生成的头文件放到当前的 jni 目录下
-o : 指定生成的头文件名称,默认以类全路径名生成(包名 + 类名. h)
注意:-d 和 - o 只能使用其中一个参数。
注意: -d D:\Demo\NDKDemo\app\src\main\jni 和 -classpath D:\Demo\NDKDemo\app\src\main\java 位置可以互换;一下写法和等价于上面的写法;
javah -classpath D:\Demo\NDKDemo\app\src\main\java -d D:\Demo\NDKDemo\app\src\main\jni com.ang.ndkdemo.MainActivity
补充:可以通过 - o 指定生成的头文件名称,如果不指定,默认以类全路径名生成(包名 + 类名. h)
javah -classpath E:\Demo\JNIDemo\app\src\main\java -o E:\Demo\JNIDemo\app\src\main\java\jni\JNITest.h com.ang.MainActivity
2,执行以上命令之后:就在项目的 main 文件夹下创建了 jni 文件夹,并且在 jni 文件夹下自动创建了. h 头文件;头文件名也是自动生成的,命名规则是 com_ang_ndkdemo_MainActivity.h(包名 + 类名. h)
3,自动生成的 com_ang_ndkdemo_MainActivity.h 头文件代码
/* DO NOT EDIT THIS FILE - it is machine generated /
#include <jni.h>
/ Header for class com_ang_ndkdemo_MainActivity */
#ifndef _Included_com_ang_ndkdemo_MainActivity
#define _Included_com_ang_ndkdemo_MainActivity
#ifdef __cplusplus
extern “C” {
#endif
/*
- Class: com_ang_ndkdemo_MainActivity
- Method: fromJNIString
- Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_ang_ndkdemo_MainActivity_fromJNIString
(JNIEnv *, jobject);
/JNIEnv 是定义任意native函数的第一个参数(包括调用JNI的RegisterNatives函数注册的函数),指向JVM函数表的指针,函数表中的每一个入口指向一个JNI函数,每个函数用于访问JVM中特定的数据结构。*/
#ifdef __cplusplus
}
#endif
#endif
4,生成. h 头文件时候,如果出现 “找不到类文件” 的错误请参考 blog.csdn.net/ezconn/arti… 这篇文章
注意:
a. 包名或类名或方法名中含下划线 _ 要用 _1 连接;
b. 重载的本地方法命名要用双下划线 __ 连接;
c. 参数签名的斜杠 “/” 改为下划线 “_” 连接,分号 “;” 改为 “_2” 连接,左方括号 “[” 改为 “_3” 连接;
另外,对于 Java 的 native 方法,static 和非 static 方法的区别在于第二个参数,static 的为 jclass,非 static 的 为 jobject;JNI 函数中是没有修饰符的。
五、在 jni 目录下创建 c 或者 c++ 文件;
文件名可以随意写,但需要注意文件类型;Hello.c 文件(.c 后缀的文件为 C)代表内容是 C 代码;Hello.cpp(.cpp 后缀的文件为 C++)文件代表内容是 C++ 代码;
C++ 代码(注意 C 和 C++ 代码是有区别),以下分别给出 C 和 C++ 两种实现方式:
- a,Hello.c 文件。在 C 中没有引用,传递的 env 是个两级指针,用(*env)-> 调用方法且方法中要传入 env.
#include <jni.h>
#include “com_ang_ndkdemo_MainActivity.h”
JNIEXPORT jstring JNICALL
Java_com_ang_ndkdemo_MainActivity_fromJNIString(JNIEnv* env, jobject obj) {
return (*env)->NewStringUTF(env,“I am From Native C”);
}
- b, Hello.cpp 文件。C++ 中 env 为一级指针,用 env-> 调用方法,无需传入 env;C++ 语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而 C 语言则不会,因此会造成链接时找不到对应函数的情况,此时 C 函数就需要用 extern “C” 进行链接指定,这告诉编译器,请保持我的名称,不要给我生成用于链接的中间函数名;exter “C”{jni 代码}。
#include <com_ang_ndkdemo_MainActivity.h>
#include <stdio.h>
JNIEXPORT jstring JNICALL
Java_com_ang_ndkdemo_MainActivity_fromJNIString(JNIEnv *env, jobject obj)
{
return env->NewStringUTF(“I am From Native C”);
}
Java 的 native 方法是如何链接 C/C++ 中的函数的呢?可以通过静态和动态的方式注册 JNI。 以上是通过静态注册的方式。
静态注册:根据函数名建立 Java 本地方法和 JNI 函数的一一对应关系。
动态注册:直接告诉 Java native 方法其在 JNI 中对应函数的指针。
六、配置 build.gradle(Model:App)
也可以不配置 ndk{}, 这里只是指定编译出哪几种对应的 abi 架构的. so 库,如果不配置,会根据 ndk-build 默认输出对应的 abi 架构的. so 库;最好配置,不然不能编译出自己想要的对应 ABI 架构的. so,如果自己的项目中已经引用其他的. so 库还要做适配;
defaultConfig {
applicationId “com.ang.demo”
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName “1.0”
testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”
//ndk编译生成.so文件
ndk{
moduleName “Java2c” //生成的so名字,Android.mk文件中已经指定了,这里可以不写
abiFilters “armeabi”, “armeabi-v7a”, “x86” //输出指定三种abi体系结构下的so库。
}
}
七、编写 Android.mk 文件
Android.mk 文件一般包含如下信息就够了,差不多可算得上一个模板;根据自己的. so 库名和 C 或者 C++ 文件名修改一下就可以用了;
LOCAL_PATH:= $(call my-dir)#不用修改
include $(CLEAR_VARS)#不用修改
LOCAL_MODULE:= hello #动态库名称
LOCAL_SRC_FILES:= hello.c #C文件,里面就是我们写的C代码
include $(BUILD_SHARED_LIBRARY)#生成.so动态库
#include $(BUILD_STATIC_LIBRARY) 编译出.a的静态库
还有一种方式,就是让 androidstudio 自动生成;如下是我获取自动生成的 Android.mk 文件的方式:
a, 紧接着步骤六之后,点击 Androidstudio 菜单栏 Build ->ReBuildProject
报错:
b, 在 app ——> build ——>intermediater——>ndk(自动创建) 目录下自动创建了一个 Android.mk 文件
最后
在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。
附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!