zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

Android Studio的JNI开发快餐教程

2023-09-14 09:04:39 时间
Android Studio的JNI开发快餐教程

从eclipse换到Android Studio之后,原来的NDK集成已经不能用了。同时,AndroidStudio也是在快速迭代进步中,不仅支持内置的ndk支持插件,还有支持外部编译系统的plugin. 而且这还是在实验中的结果,在不久的将来,还可能有更新的变化。不过,万变不离其宗,我们打好基础,形式上的东西跟着Android Studio变就好。

旧式的NDK支持

首先说明,既然是Android Studio认为它已经过时了,所以我们需要在gradle.properties中声明一下我们还坚持用这个属性:

android.useDeprecatedNdk=true

下面我们看下,在build.gradle中如何使用这种老式的办法:

apply plugin: com.android.application

 android {

 compileSdkVersion 24

 buildToolsVersion "24.0.0"

 defaultConfig {

 applicationId "com.yunos.xulun.testcppjni"

 minSdkVersion 21

 targetSdkVersion 24

 versionCode 1

 versionName "1.0"

 ndk{

 moduleName "testcppjni"

 buildTypes {

 release {

 minifyEnabled false

 proguardFiles getDefaultProguardFile(proguard-android.txt), proguard-rules.pro

 }

这其中使用的plugin,是"com.android.application".

我们现在可以开始写一个类测试一下:

package com.yunos.xulun.testcppjni;

public class TestCppJni {

 static{

 System.loadLibrary("testcppjni");

 public static native int callCpp();

}

编译之后,使用javah工具生成头文件com_yunos_xulun_testcppjni_TestCppJni.h:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include jni.h 

/* Header for class com_yunos_xulun_testcppjni_TestCppJni */

#ifndef _Included_com_yunos_xulun_testcppjni_TestCppJni

#define _Included_com_yunos_xulun_testcppjni_TestCppJni

#ifdef __cplusplus

extern "C" {

#endif

 * Class: com_yunos_xulun_testcppjni_TestCppJni

 * Method: callCpp

 * Signature: ()I

JNIEXPORT jint JNICALL Java_com_yunos_xulun_testcppjni_TestCppJni_callCpp

 (JNIEnv *, jclass);

#ifdef __cplusplus

#endif

#endif

然后我们写一个C++函数去实现它:

#include "com_yunos_xulun_testcppjni_TestCppJni.h"

JNIEXPORT jint JNICALL Java_com_yunos_xulun_testcppjni_TestCppJni_callCpp

 (JNIEnv *env, jclass obj){

 return (jint)0;

}

将头文件和cpp文件放到app/src/main/jni下面。

在Android工程中写个类去引用这个本地方法,就不多说了。编译运行,就生成了libtestcppjni.so。

还可以额外多设几个属性,比如编译选项,比如生成什么架构的库,引入什么库等等:

 android {

 compileSdkVersion 24

 buildToolsVersion "24.0.0"

 defaultConfig {

 applicationId "com.yunos.xulun.testcppjni"

 minSdkVersion 21

 targetSdkVersion 24

 versionCode 1

 versionName "1.0"

 ndk{

 moduleName "testcppjni"

 cFlags "-std=c++11"

 abiFilters "arm64-v8a","armeabi", "armeabi-v7a", "x86"

 ldLibs "log"

 buildTypes {

 release {

 minifyEnabled false

 proguardFiles getDefaultProguardFile(proguard-android.txt), proguard-rules.pro

 }
新的实验性的编译系统的NDK支持

其实,新的实验性编译系统,对于java的编译也是变了不少。

下面,我们follow步骤去升级到新的编译系统:

升级gradle的版本

首先,要确保gradle的版本在2.10以上,我们通过修改gradle/wrapper下的gradle-wrapper.properties中的distributionUrl来实现这一点。

distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
升级plug-in

我们修改build.gradle,从正式版改成实验版,在我写这篇文件时,最新版本是0.8.0-alpah5。我们保守点,选个不带alpha的0.7.2:

buildscript {

 repositories {

 jcenter()

 dependencies {

 classpath com.android.tools.build:gradle-experimental:0.7.2

 // NOTE: Do not place your application dependencies here; they belong

 // in the individual module build.gradle files

}

经过上一步的修改,系统已经提示,无法找到我们之前用的"com.android.application"的包名了,所以我们要针对新的com.android.model.applicaiton’包进行修改:

apply plugin: com.android.model.application

model {

 android {

 compileSdkVersion 24

 buildToolsVersion "24.0.0"

 defaultConfig {

 applicationId "com.yunos.xulun.testcppjni"

 minSdkVersion.apiLevel 21

 targetSdkVersion.apiLevel 24

 versionCode 1

 versionName "1.0"

 buildConfigFields{

 create() {

 type "int"

 name "VALUE"

 value "1"

 ndk {

 moduleName "testcppjni"

 cppFlags.add("-std=c++11")

 ldLibs.add("log")

 buildTypes {

 release {

 minifyEnabled false

 proguardFiles.add(file(proguard-rules.pro))

 productFlavors{

 create("Flavor"){

 applicationId "com.yunos"

dependencies {

 compile fileTree(dir: libs, include: [*.jar])

 testCompile junit:junit:4.12

 compile com.android.support:appcompat-v7:24.0.0

}

针对ndk部分,moduleName部分不用变。但是像cppFlags和ldLibs现在要通过add方法来进行添加了。

我们还可以加上调试和stl的支持:

apply plugin: com.android.model.application

model {

 android {

 compileSdkVersion 24

 buildToolsVersion "24.0.0"

 defaultConfig {

 applicationId "com.yunos.xulun.testcppjni"

 minSdkVersion.apiLevel 21

 targetSdkVersion.apiLevel 24

 versionCode 1

 versionName "1.0"

 buildConfigFields{

 create() {

 type "int"

 name "VALUE"

 value "1"

 ndk {

 moduleName "testcppjni"

 cppFlags.add("-std=c++11")

 ldLibs.add("log")

 stl "stlport_shared"

 buildTypes {

 release {

 minifyEnabled false

 proguardFiles.add(file(proguard-rules.pro))

 ndk{

 debuggable true

 productFlavors{

 create("Flavor"){

 applicationId "com.yunos"

dependencies {

 compile fileTree(dir: libs, include: [*.jar])

 testCompile junit:junit:4.12

 compile com.android.support:appcompat-v7:24.0.0

}
直接调用NDK或者CMake

上面这两种方式还不算完,生命不息,折腾不止,让我们一起跟随Android Studio继续折腾。
从2.2版本开始,Android Studio开始在64位OS上支持

这次我们直接调用NDK去build。
之前我们一直没有写Android.mk,现在要用NDK了,就写一个吧:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := testcppjni

LOCAL_SRC_FILES := test.cpp

LOCAL_CFLAGS += -std=c++11

LOCAL_ARM_MODE := thumb

include $(BUILD_SHARED_LIBRARY)

Application.mk也写个吧:

APP_ABI := armeabi armeabi-v7a arm64-v8a

然后改build.gradle:

android {

 compileSdkVersion 20

 buildToolsVersion "24.0.0"

 externalNativeBuild{

 ndkBuild{

 path "Android.mk"

 defaultConfig {

 applicationId "com.yunos.xulun.testcppjni"

 minSdkVersion 19

 targetSdkVersion 19

 externalNativeBuild {

 ndkBuild {

 targets "testcppjni"

 arguments "NDK_APPLICATION_MK:=Application.mk"

 cppFlags "-std=c++11"

 abiFilters "armeabi-v7a", "armeabi","arm64-v8a"

 }

从目前的情况看,可以继续用过时的老方法,因为后两种都还没有正式发布。
有兴趣的可以跟进新的编译系统,升级到2.2之后,也可以考虑使用externalNativeBuild。


❤️【Android精进之路-02】安装Android Studio,认识Android SDK,一步步学习❤️ 上一篇文章定好了Android学习计划,这篇文章就正式进入Android的学习之旅了。本文将重点介绍Android SDK的目录结构,如何安装Android Studio以及如何用Android Studio进行第一个Android应用的开发。
lusing 刘子瑛,阿里系统框架专家。工作十余年,一直对新编程语言、新开发方法、数学与算法相关和并发等相关领域保持浓厚的兴趣。乐于通过技术分享促进新技术。