Android 中Native方法是怎样调用的

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 中Native方法是怎样调用的相关的知识,希望对你有一定的参考价值。

通过jni接口调用native

步骤如下:

1.创建一个 android project, 名字叫Why

2 在工程Why中添加一个Java类,class名为Jni。这个类是一个JNI接口的Java类,文件名为Jni.java。
package com.yarin.android.Why;
public class Jni
public native int getCInt();
public native String getCString();


3.将工程Why下的 "src\com\yarin\android\Why" 目录下的Jni.java文件copy到“Why\bin\classes”下.
4.Generate Jni.class file via the command below:
javac jni.java
Then copy the Jni.class file generated to cover and replace the original Jni.class file in directory “Why\bin\classes\com\yarin\android\Why”.
------The original Jni.class file, you must build the java project first to generate it.

5.Generate c style header file
javah –classpath C:\android-ndk-r6b\myproject\Why\bin\classes com.yarin.android.Why.Jni
com.yarin.android.Why is my package name appeared in Jni.java file.

com_yarin_android_Why_Jni.h is like below:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_yarin_android_Why_Jni */
#ifndef _Included_com_yarin_android_Why_Jni
#define _Included_com_yarin_android_Why_Jni
#ifdef __cplusplus
extern "C"
#endif
/*
* Class: com_yarin_android_Why_Jni
* Method: getCInt
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_yarin_android_Why_Jni_getCInt
(JNIEnv *env, jobject object); ---you need to supplement the parameter name yourself
/*
* Class: com_yarin_android_Why_Jni
* Method: getCString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_yarin_android_Why_Jni_getCString
(JNIEnv *env, jobject object);
#ifdef __cplusplus

#endif
#endif

6.Add com_yarin_android_Why_Jni.c file corresponding to the above c style header file, then add implemented code.

#include <stdio.h>
#include <stdlib.h>
#include "com_yarin_android_Why_Jni.h"

int add()

int x,y;
x = 111;
y = 22;
x += y;

return x;


JNIEXPORT jint JNICALL Java_com_yarin_android_Why_Jni_getCInt
(JNIEnv *env, jobject object)

return add();


JNIEXPORT jstring JNICALL Java_com_yarin_android_Why_Jni_getCString
(JNIEnv *env, jobject object)

(*env)->NewStringUTF(env, " Why is ok ^_^ ----->> ");


7.然后实现在工程Why下创建目录jni,并且copy com_yarin_android_Why_Jni.c /h 到jni目录下。

8.在"Why\jni"目录下编写Android.mk ,在"android-ndk-r6b\jni"下编写Application.mk , 然后在NDK环境下编译native code,生成动态库libWhy.so。

9.在java工程中加入调用native 动态库的代码:

package com.yarin.android.Why;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class WhyActivity extends Activity
static

System.loadLibrary("Why");

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
Jni jni = new Jni();
TextView view = new TextView(this);
view.setText(jni.getCString() + Integer.toString(jni.getCInt()));
setContentView(view);



10 编译Why工程,然后 run as Android Application, 就能看到native code的调用结果了。

Tip:

Usage of the command javah.

javah -d <outputdir> -classpath <classpath> <fully_qualified_class>

where:

'outputdir' is the directory where to put the generated header file

'classpath' contains an absolute path to the directory containing your root package (as mentionned by Glen)

'fully_qualified_class' is the name of the class containing native methods without .class extension

-jni option is not required (set by default)
参考技术A 1. Power.java--> find corresponding native cfile(查找对应的具体用C实现的C文件)
android.os.Power.java -------- native file ---->.../jni/android_os_Power.c

2. in android_os_Power.c, you canfind:

static JNINativeMethod method_table[]= // Native functiontable

"acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock,
"releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock,
"setLastUserActivityTimeout", "(J)I",(void*)setLastUserActivityTimeout ,
"setScreenState", "(Z)I", (void*)setScreenState ,
"shutdown", "()V", (void*)android_os_Power_shutdown ,
"reboot","(Ljava/lang/String;)V", (void*)android_os_Power_reboot ,
;

int register_android_os_Power(JNIEnv *env)// function to register mapping tablefrom name to function

returnAndroidRuntime::registerNativeMethods(
env, "android/os/Power",
method_table, NELEM(method_table));

3. in /framework/base/core/jni , a file named:AndroidRuntime.cpp

3.1) a global register function array
static const RegJNIRec gRegJNI[] =

...
register_android_os_Power,


3.2) Register native function process
int AndroidRuntime::startReg(JNIEnv* env)
or
Java_com_android_internal_util_WithFramework_registerNatives(...)
or
Java_LoadClass_registerNatives(....)
---> register_jni_procs(gRegJNI, NELEM(gRegJNI),env)
---> foreach(member of gRegJNI) call register_XXX_XXX_XXX..XXX() //so here register_android_os_power() will becalled
---> AndroidRuntime::registerNativeMethods(env, class_namelike "android/os/Power", method table like method_table,size)
---> jniRegisterNativeMethods(env, className,gMethods, numMethods)
-->pEnv->RegisterNatives(env, clazz, gMethods,numMethods) ;
--> foreach(method) calldvmRegisterJNIMethod(ClassObject* clazz, const char*methodName,
constchar* signature, void* fnPtr)
--> calldvmSetNativeFunc(method, dvmCallSynchronizedJNIMethod, fnPtr); //for sycn method
or
call dvmSetNativeFunc(method, dvmCallJNIMethod,fnPtr);
--> ((Method*)method)->insns = insns; // set actual codespace to be executed for a native function

4.calling a native method ( JNI method)
void dvmPlatformInvoke(void* pEnv,ClassObject* clazz, int argInfo, int argc,
const u4*argv, const char* shorty, void* func, JValue*pReturn)
dvmCallMethod() /dvmInvokeMethod
---> if(dvmIsNativeMethod(method))

(*method->nativeFunc)(self->curFrame,&retval, method, self);
本回答被提问者采纳

JavaScript如何调用Native iOS/Android 方法

写在前面的话:本文面向web前端工程师,iOS 或 Android 请移步这里stackoverflow。关于app开发模式,这里不再赘述。

一、判断机型

js 调用 Native iOS/Android function 需要使用不同的方法,所以首先要做的是判断用户机型,代码如下:

var u = navigator.userAgent.toLowerCase();
var isApple = /iphone|ipad|ipod|ios/i.test(u);
var isAndroid = /android/i.test(u);

二、调用 Native iOS 方法

通过 js 改变 window.location 值, 来实现调用 iOS function ,这个操作并不是跳转,而是触发了一个 即发即弃 (a fire and forget) 事件。代码如下:

//一个参数
window.location = ‘color://‘ + color;

//两个参数
window.location = ‘myscheme://param1/‘ + value1 + ‘/param2/‘ + value2;

iOS 端接收参数需要进行 url 编码处理,可以使用 encodeURIComponent 函数处理。

ps:关于URI和URL
URI(Uniform Resource Identifier) 统一资源标识符
URL(Uniform Resource Locator) 统一资源定位符
URI包含URL和URN,如果URI标识一个人,URL好比这个人的住址,URN则是名字。

三、调用 Native Andriod 方法

与 iOS 不同之处在于,Andriod 接收中文英文参数,无需 encode 操作。实现代码如下:

if(window.AndroidBridge) {
    window.AndroidBridge.changeNavbarBackground(color);
}

四、关于函数名称约定

三方会根据业务需求定义一个通用的函数名称,这个函数名称通常是由web前端工程师定义的。例如,我想要获取用户id,本着驼峰命名规范,我们将函数名称统一定义为 getId() 。在 iOS 调试时,发现iOS接收到的函数方法为 getid() ,导致bug。

ok,问题解决了,若还有其他问题,欢迎给我留言。如果对你有帮助,记得在下方点个推荐吧~~

本文转载于:猿2048?https://www.mk2048.com/blog/blog.php?id=hh1bbih0h0j

以上是关于Android 中Native方法是怎样调用的的主要内容,如果未能解决你的问题,请参考以下文章

Unity在Android和iOS中如何调用Native API

cordova混合开发:Android中native调用javascript

JavaScript如何调用Native iOS/Android 方法

android中怎么手动调用.so库中的游戏,

在android中安排后台任务并从任务中调用react-native javascript方法

Unity 调用 Android Native 方法 获得Android系统音量