Android的Jni教程

54

大家好,有没有人能向我推荐一些学习Android JNI的好资源以及一些好的JNI教程?


16
在我看来,这是一个完全有效的问题,因为它已经被浏览了14000次。在这种情况下,人们想要阅读的是不同的意见。工程师对他们处理流程的方法持有不同的观点。至于吸引垃圾信息,stackoverflow显然可以应对这个小问题。下面的答案很有帮助,更多有用的答案是这个网站的目的。 - R Earle Harris
1
有一个来自谷歌的代码实验室。 https://codelabs.developers.google.com/codelabs/android-studio-jni/index.html?index=..%2F..%2Findex#0 - Cüneyt
2个回答

51

ECLIPSE教程

这里有两个小教程, 第一个链接和第二个链接。如果你想编写一个使用JNI的简单程序,可以继续阅读。

创建Android应用程序项目,一旦项目被创建,您需要在项目的顶层创建一个新文件夹。右键单击项目名称 → 新建 → 文件夹。将其命名为jni。然后添加名为SquaredWrapper的类,并将以下代码添加到其中:

package org.edwards_research.demo.jni;

public class SquaredWrapper {
    // Declare native method (and make it public to expose it directly)
    public static native int squared(int base);

    // Provide additional functionality, that "extends" the native method
    public static int to4(int base)
    {
        int sq = squared(base);
        return squared(sq);
    }

    // Load library
    static {
        System.loadLibrary("square");
    }
} 

打开终端。您必须编译这些代码以获取头文件。首先调用此命令。

cd src # change into the source directory
javac -d /tmp/ org/edwards_research/demo/jni/SquaredWrapper.java
比之前更胜一筹。
cd /tmp
javah -jni org.edwards_research.demo.jni.SquaredWrapper

所以你将在tmp目录中拥有名为org.edwards_research.demo.jni.SquaredWrapper的头文件。

它应该长这个样子

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_edwards_research_demo_jni_SquaredWrapper */

#ifndef _Included_org_edwards_research_demo_jni_SquaredWrapper
#define _Included_org_edwards_research_demo_jni_SquaredWrapper
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     org_edwards_research_demo_jni_SquaredWrapper
 * Method:    squared
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared
  (JNIEnv *, jclass, jint);

#ifdef __cplusplus
}
#endif
#endif

为了您的方便,将这些名称更改为简短的名称,例如square.h。将此头文件复制到应用程序的jni文件夹中。然后在同一文件夹中创建square.c文件,并将其复制到其中。

 #include "square.h"

JNIEXPORT jint JNICALL Java_com_example_android_1jni_1second_1demo_SquaredWrapper_squared
      (JNIEnv * je, jclass jc, jint base)
    {
            return (base*base);
    }

将此添加到您的 MainActivity.java

int x = SquaredWrapper.to4(2);
        x = x*2;

jni 文件夹中添加以下 Android.mk 文件:

    LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := squared
LOCAL_SRC_FILES := square.c

include $(BUILD_SHARED_LIBRARY)

必须从头文件和cpp文件创建库。

所以您只需要查看我的第一个链接,进行一些配置,现在可以编译它,确保您的库已创建并且lib目录包含它。

Android Studio教程

假设您已经在Android Studio中打开了简单的Android应用程序

步骤1:在Android Studio中打开您的应用程序

步骤2:下载NDK并将路径设置为应用程序的本地属性(在android sdk路径之前/之后),如下ndk.dir=C\:\\Android\\android-ndk-r10e

注:Windows需要双反斜杠,Linux只需要一个正斜杠

步骤3:在应用程序中添加JNI文件夹(右键单击应用程序->新建->文件夹->JNI文件夹)

步骤4:通过以下方式设置Gradle

app/build.gradle中添加此代码以启动NDK

   sourceSets.main {
        jni.srcDirs = []
        jniLibs.srcDir 'src/main/libs'
    }

    tasks.withType(NdkCompile) { // disable automatic ndk-build call
    compileTask -> compileTask.enabled = false
    }

    task ndkBuild(type: Exec) { // call ndk-build(.cmd) script
        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
            commandLine 'cmd', '/c', 'ndk-build.cmd', '-C', file('src/main').absolutePath
        } else {
            commandLine 'ndk-build', '-C', file('src/main').absolutePath
        }

   tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }

步骤4:

在应用的JNI文件夹中创建Android.mk和Application.mk文件,并使用以下内容:

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := main
LOCAL_SRC_FILES := main.cpp

include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_ABI := all
include $(BUILD_SHARED_LIBRARY)

在APP_ABI中,您可以选择使用哪些编译器。

步骤5:

因为我们从build.config中禁用了NDK,所以我们必须手动运行它。要在src\main\jn文件夹中创建com_example_nativedemo_app_MainActivit.h文件,我们需要在终端中运行此命令。

javah -d .\jni -classpath C:\Intel\INDE\IDEintegration\android-sdk-windows\platforms\android-21\android.jar;..\..\build\intermediates\classes\debug com.example.mydemo.nativedemo.MainActivity

对于Windows命令提示符,您需要提供文件的完整路径。

步骤6:

在JNI文件夹中添加文件main.cpp,并使用以下内容:

#include <string.h>
#include <jni.h>
#include <vchat_cpptest_Hellojnicpp.h>

extern "C" {
      JNIEXPORT jstring JNICALL
      Java_vchat_cpptest_Hellojnicpp_stringFromJNI
      (JNIEnv *env, jobject obj)
      {
            #ifdef __INTEL_COMPILER_UPDATE
              return env->NewStringUTF("Hello from Intel C++ over JNI!");
          #else
              return env->NewStringUTF("Hello from default C++ over JNI!");
          #endif
}

17

我建议下载ndk。解压缩并浏览示例文件夹ndk代码。从hello-jni开始,逐步深入了解。它易于理解并解释了很多问题。 您还可以同时浏览这些链接这个链接以及在查看代码时来回参考此文档


你可以在我的 Github 页面上找到一个使用 Android Studio 的 JNI 实战项目:https://github.com/russell-shizhen/JniExample。我尽可能地提供了 JNI API 使用的示例。 - shizhen
我认为与ndk相关的代码示例现在已经从ndk文件夹中删除了。 我在下面的位置找到了相同的内容。 https://github.com/android/ndk-samples - Karthik H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接