導航:首頁 > 操作系統 > androidenv

androidenv

發布時間:2022-06-10 21:37:40

A. 怎麼在android java setenv

安卓機普遍會有備份通訊錄的功能,備份的文件一般存儲在內存卡中具體那個文件夾視手機而定,如果你的Java無系統手機有導入通訊錄備份的功能,並且導入備份的文件支持你安卓機導出的備份文件,這樣你把安卓機備份的通訊錄文件拷貝到java無系統手機的內存卡中,直接導入通訊錄備份文件。不過這個只是我的猜想,我沒有試過,但是大膽的猜測下,不可行的幾率會大些。 ----------------哥割哥---------------- 樓上的方法也許更值得一試。

B. 如何在android源碼中添加自己的jni方法

1,、項目實現了一個簡單的四則運算,項目的目錄層次如下:

AndroidManifest.xml Android.mk jni res src

資源文件簡簡單單,一個布局文件,稍後會有demo的下載地址

主要記錄備忘的內容如下:

MainActivity.Java

[html] view plain public native int add(int x, int y);

public native int substraction(int x, int y);

public native float multiplication(int x, int y);

public native float division(int x, int y);

static{

System.loadLibrary("arithmetic");

}

2、生成lib的名稱為libarithmetic.so.注意load的時候寫"arithmetic"

jni 目錄下有兩個文件,一個是Android.mk,一個是c++源文件long.cpp

jni/Android.mk如下:

[html] view plain LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_MODULE:= libarithmetic

LOCAL_SRC_FILES:= \

long.cpp

LOCAL_SHARED_LIBRARIES := \

libutils

LOCAL_STATIC_LIBRARIES :=

LOCAL_C_INCLUDES += \

$(JNI_H_INCLUDE)

LOCAL_CFLAGS +=

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

3、注釋:

LOCAL_PATH(必須定義,而且要第一個定義),宏函數『my-dir』, 由編譯系統提供,用於返回當前路徑(即包含Android.mk
file文件的目錄);

include $( CLEAR_VARS),

CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變數(例如 LOCAL_MODULE,
LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH
。這是必要的,因為所有的編譯控制文件都在同一個GNU MAKE執行環境中,所有的變數都是全局的;

LOCAL_MODULE_TAGS :=user eng tests optional

user: 指該模塊只在user版本下才編譯

eng: 指該模塊只在eng版本下才編譯

tests: 指該模塊只在tests版本下才編譯

optional:指該模塊在所有版本下都編譯

LOCAL_MODULE(必須定義),標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包含任何空格。Note:編譯系統會自動產生合適的前綴和後綴,例如:arithmetic編譯成功後將生成libarithmetic.so庫文件

LOCAL_SRC_FILES 變數必須包含將要編譯打包進模塊中源代碼文件。不用在這里列出頭文件和包含文件。

LOCAL_SHARED_LIBRARIES中加入所需要鏈接的動態庫(*.so)的名稱

LOCAL_STATIC_LIBRARIES加入所需要鏈接的靜態庫(*.a)的名稱

LOCAL_CFLAG可選的編譯器選項,用法之一是定義宏,例如LOCAL_CFLAGS := -Werror作用是編譯警告也作為錯誤信息

LOCAL_PRELINK_MODULE:=false,不作prelink處理,默認是要prelink操作的,有可能造成地址空間沖突(這地方目前還不明白)
long.cpp源代碼如下:

[html] view plain #define LOG_TAG "LongTest2 long.cpp"

#include

#include

#include "jni.h"

jint add(JNIEnv *env, jobject thiz, jint x, jint y){

return x + y;

}

jint substraction(JNIEnv *env, jobject thiz, jint x, jint y){

return x - y;

}

jfloat multiplication(JNIEnv *env, jobject thiz, jint x, jint y){

return (float)x * (float)y;

}

jfloat division(JNIEnv *env, jobject thiz, jint x, jint y){

return (float)x/(float)y;

}

static const char *classPathName = "com/inspur/test2/MainActivity";

static JNINativeMethod methods[]= {

{"add", "(II)I", (void*)add},

{"substraction", "(II)I", (void*)substraction},

{"multiplication", "(II)F", (void*)multiplication},

{"division", "(II)F", (void*)division},

};

typedef union{

JNIEnv* env;

void* venv;

}UnionJNIEnvToVoid;

static int registerNativeMethods(JNIEnv* env, const char* className,

JNINativeMethod* gMethods, int numMethods){

jclass clazz;

clazz = env->FindClass(className);

if (clazz == NULL)

return JNI_FALSE;

if (env->RegisterNatives(clazz, gMethods, numMethods)<0)

return JNI_FALSE;

return JNI_TRUE;

}

static int registerNatives(JNIEnv *env){

if (!registerNativeMethods(env, classPathName,

methods, sizeof(methods)/sizeof(methods[0])))

{

return JNI_FALSE;

}

return JNI_TRUE;

}

jint JNI_OnLoad(JavaVM* vm, void* reserved){

UnionJNIEnvToVoid uenv;

uenv.venv = NULL;

jint result = -1;

JNIEnv *env = NULL;

if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK){

goto l;

}

env = uenv.env;

env = uenv.env;

if (registerNatives(env) != JNI_TRUE){

goto l;

}

result = JNI_VERSION_1_4;

l:

return result;

}

除了利用 編寫native JAVA類,通過javah生成.h文件,根據.h文件編寫.c/cpp文件
方法外(名字像老太太的裹腳步,又臭又長,而且不靈活),Android還可以通過引用JNI_Onload方式實現。jint JNI_onLoad(JavaVM*
vm, void* reverced),改方法在so文件被載入時調用。

JNI_OnLoad()有兩個重要的作用:

指定JNI版本:告訴VM該組件使用那一個JNI版本(若未提供JNI_OnLoad()函數,VM會默認該使用最老的JNI
1.1版),如果要使用新版本的JNI,例如JNI
1.4版,則必須由JNI_OnLoad()函數返回常量JNI_VERSION_1_4(該常量定義在jni.h中) 來告知VM。

初始化設定,當VM執行到System.loadLibrary()函數時,會立即先呼叫JNI_OnLoad()方法,因此在該方法中進行各種資源的初始化操作最為恰當。

JNI_OnUnload()的作用與JNI_OnLoad()對應,當VM釋放JNI組件時會呼叫它,因此在該方法中進行善後清理,資源釋放的動作最為合適。

4、項目根目錄下Android.mk文件:

[html] view plain LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_JNI_SHARED_LIBRARIES := libarithmetic

LOCAL_PACKAGE_NAME := LongTest

LOCAL_SHARED_LIBRARIES := \

libutils\

liblog

include $(BUILD_PACKAGE)

include $(LOCAL_PATH)/jni/Android.mk

# Also build all of the sub-targets under this one: the shared library.

include $(call all-makefiles-under,$(LOCAL_PATH))

LOCAL_PACKAGE_NAME:項目名稱,即最終生成apk的名字

LOCAL_JNI_SHARED_LIBRARIES := libxxx就是把so文件放到apk文件里的libs/armeabi里

執行BUILD_PACKAGE。它的定義也是在config.mk中定義如下:BUILD_PACKAGE:=
$(BUILD_SYSTEM)/package.mk

$(call all-java-files-under, src)編譯的源代碼文件列表添加src目錄下所有的java 源文件

$(call all-makefiles-under, $(LOCAL_PATH))編譯器會在編譯完當前目錄下的文件後再深入子目錄編譯

如果make過android源碼,可以在項目根目錄下執行mm命令進行編譯。前提是執行過source
androidSRC/build/envsetup.sh

或者直接把source androidSRC/build/envsetup.sh添加到~/.bashrc中,會更加方便

C. android應用是如何監聽自己是否被卸載的呢

Activity啟動時fork出C端進程輪詢目錄:

1 package main.activity;
2
3 import pym.test.uninstalledmoniter.R;
4 import android.app.Activity;
5 import android.os.Bundle;
6 import android.util.Log;
7
8 /**
9 * @author pengyiming
10 * @note 監聽此應用是否被卸載,若被卸載則彈出卸載反饋
11 *
12 */
13
14 public class UninstalledMoniterActivity extends Activity
15 {
16 /* 數據段begin */
17 private static final String TAG = "UninstalledMoniterActivity";
18 /* 數據段end */
19
20 /* 函數段begin */
21 private native void init();
22 static
23 {
24 Log.d(TAG, "load libuninstalled_moniter");
25 System.loadLibrary("uninstalled_moniter");
26 }
27
28 @Override
29 public void onCreate(Bundle savedInstanceState)
30 {
31 super.onCreate(savedInstanceState);
32 Log.d(TAG, "onCreate");
33
34 setContentView(R.layout.uninstalled_moniter_layout);
35
36 init();
37 }
38 /* 函數段end */
39 }

核心——native方法頭文件:

1 /* 頭文件begin */
2 #include <jni.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <android/log.h>
6 #include <unistd.h>
7 /* 頭文件end */
8
9 /* 宏定義begin */
10 //清0宏
11 #define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize)
12
13 //LOG宏定義
14 #define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg)
15 #define LOG_DEBUG(tag, msg) __android_log_write(ANDROID_LOG_DEBUG, tag, msg)
16 #define LOG_WARN(tag, msg) __android_log_write(ANDROID_LOG_WARN, tag, msg)
17 #define LOG_ERROR(tag, msg) __android_log_write(ANDROID_LOG_ERROR, tag, msg)
18 /* 宏定義end */
19
20 #ifndef _Included_main_activity_UninstalledMoniterActivity
21 #define _Included_main_activity_UninstalledMoniterActivity
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 #undef main_activity_UninstalledMoniterActivity_MODE_PRIVATE
27 #define main_activity_UninstalledMoniterActivity_MODE_PRIVATE 0L
28 #undef main_activity_UninstalledMoniterActivity_MODE_WORLD_READABLE
29 #define main_activity_UninstalledMoniterActivity_MODE_WORLD_READABLE 1L
30 #undef main_activity_UninstalledMoniterActivity_MODE_WORLD_WRITEABLE
31 #define main_activity_UninstalledMoniterActivity_MODE_WORLD_WRITEABLE 2L
32 #undef main_activity_UninstalledMoniterActivity_MODE_APPEND
33 #define main_activity_UninstalledMoniterActivity_MODE_APPEND 32768L
34 #undef main_activity_UninstalledMoniterActivity_MODE_MULTI_PROCESS
35 #define main_activity_UninstalledMoniterActivity_MODE_MULTI_PROCESS 4L
36 #undef main_activity_UninstalledMoniterActivity_BIND_AUTO_CREATE
37 #define main_activity_UninstalledMoniterActivity_BIND_AUTO_CREATE 1L
38 #undef main_activity_UninstalledMoniterActivity_BIND_DEBUG_UNBIND
39 #define main_activity_UninstalledMoniterActivity_BIND_DEBUG_UNBIND 2L
40 #undef main_activity_UninstalledMoniterActivity_BIND_NOT_FOREGROUND
41 #define main_activity_UninstalledMoniterActivity_BIND_NOT_FOREGROUND 4L
42 #undef main_activity_UninstalledMoniterActivity_BIND_ABOVE_CLIENT
43 #define main_activity_UninstalledMoniterActivity_BIND_ABOVE_CLIENT 8L
44 #undef main_activity_UninstalledMoniterActivity_BIND_ALLOW_OOM_MANAGEMENT
45 #define main_activity_UninstalledMoniterActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
46 #undef main_activity_UninstalledMoniterActivity_BIND_WAIVE_PRIORITY
47 #define main_activity_UninstalledMoniterActivity_BIND_WAIVE_PRIORITY 32L
48 #undef main_activity_UninstalledMoniterActivity_BIND_IMPORTANT
49 #define main_activity_UninstalledMoniterActivity_BIND_IMPORTANT 64L
50 #undef main_activity_UninstalledMoniterActivity_BIND_ADJUST_WITH_ACTIVITY
51 #define main_activity_UninstalledMoniterActivity_BIND_ADJUST_WITH_ACTIVITY 128L
52 #undef main_activity_UninstalledMoniterActivity_CONTEXT_INCLUDE_CODE
53 #define main_activity_UninstalledMoniterActivity_CONTEXT_INCLUDE_CODE 1L
54 #undef main_activity_UninstalledMoniterActivity_CONTEXT_IGNORE_SECURITY
55 #define main_activity_UninstalledMoniterActivity_CONTEXT_IGNORE_SECURITY 2L
56 #undef main_activity_UninstalledMoniterActivity_CONTEXT_RESTRICTED
57 #define main_activity_UninstalledMoniterActivity_CONTEXT_RESTRICTED 4L
58 #undef main_activity_UninstalledMoniterActivity_RESULT_CANCELED
59 #define main_activity_UninstalledMoniterActivity_RESULT_CANCELED 0L
60 #undef main_activity_UninstalledMoniterActivity_RESULT_OK
61 #define main_activity_UninstalledMoniterActivity_RESULT_OK -1L
62 #undef main_activity_UninstalledMoniterActivity_RESULT_FIRST_USER
63 #define main_activity_UninstalledMoniterActivity_RESULT_FIRST_USER 1L
64 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DISABLE
65 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DISABLE 0L
66 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DIALER
67 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_DIALER 1L
68 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SHORTCUT
69 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SHORTCUT 2L
70 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_LOCAL
71 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
72 #undef main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_GLOBAL
73 #define main_activity_UninstalledMoniterActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
74
75 /*
76 * Class: main_activity_UninstalledMoniterActivity
77 * Method: init
78 * Signature: ()V
79 */
80 JNIEXPORT void JNICALL Java_main_activity_UninstalledMoniterActivity_init(JNIEnv *, jobject);
81
82 #ifdef __cplusplus
83 }
84 #endif
85 #endif

核心——native方法實現:

1 /* 頭文件begin */
2 #include "main_activity_UninstalledMoniterActivity.h"
3 /* 頭文件end */
4
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8
9 /* 內全局變數begin */
10 static char c_TAG[] = "UninstalledMoniterActivity.init";
11 static jboolean b_IS_COPY = JNI_TRUE;
12 /* 內全局變數 */
13
14 /*
15 * Class: main_activity_UninstalledMoniterActivity
16 * Method: init
17 * Signature: ()V
18 */
19 JNIEXPORT void JNICALL Java_main_activity_UninstalledMoniterActivity_init(JNIEnv *env, jobject obj)
20 {
21 jstring tag = (*env)->NewStringUTF(env, c_TAG);
22
23 //初始化log
24 LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
25 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "init OK"), &b_IS_COPY));
26
27 //fork子進程,以執行輪詢任務
28 pid_t pid = fork();
29 if (pid < 0)
30 {
31 //出錯log
32 LOG_ERROR((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
33 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "fork error !!!"), &b_IS_COPY));
34 }
35 else if (pid == 0)
36 {
37 //子進程輪詢"/data/data/pym.test.uninstalledmoniter"目錄是否存在,若不存在則說明已被卸載
38 while (1)
39 {
40 FILE *p_file = fopen("/data/data/pym.test.uninstalledmoniter", "r");
41 if (p_file != NULL)
42 {
43 fclose(p_file);
44
45 //目錄存在log
46 LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
47 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "I'm OK !!!"), &b_IS_COPY));
48
49 sleep(1);
50 }
51 else
52 {
53 //目錄不存在log
54 LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY)
55 , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "I'm NOT OK !!!"), &b_IS_COPY));
56
57 //執行命令am start -a android.intent.action.VIEW -d http://shouji.360.cn/web/uninstall/uninstall.html
58 execlp("am", "am", "start", "-a", "android.intent.action.VIEW", "-d", "http://shouji.360.cn/web/uninstall/uninstall.html", (char *)NULL);
59 }
60 }
61 }
62 else
63 {
64 //父進程直接退出,使子進程被init進程領養,以避免子進程僵死
65 }
66 }
67
68 #ifdef __cplusplus
69 }
70 #endif

注1:為了調試方便,包含<android/log.h>,使得so在執行過程中也可以像Java端一樣方便得打出log。相應的mk文件需要加上以下兩句聲明
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog

D. 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文件到「Why\bin\classes」下.
4.Generate Jni.class file via the command below:
javac jni.java
Then 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,並且 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)

E. android開發 如何在jni本地代碼 訪問自己寫的類。如何使用env->findclass

jclass GpsInfoClass = env->FindClass("com/parser/GPSINFO");
jfieldID ID_bValid = env->GetFieldID(GpsInfoClass,"bValid","I");
jfieldID ID_bSpeed = env->GetFieldID(GpsInfoClass,"bSpeed","I");
env->SetIntField(_obj,ID_bValid,(jint)info.bValid);
env->SetIntField(_obj,ID_bSpeed,(jint)info.bSpeed);
return _obj;
以上就可以了。但是不知道你的BYTE是自定義的什麼類型,如果是char之類的,就另外想辦法轉換成jint。其中 _obj 變數是public native GPSINFO getGpsInfo();這個本地方法在C代碼中的參數:JNIEXPORT jobject JNICALL Java_com_parser_GPSINFO_ getGpsInfo(JNIEnv *env, jobject _obj)

F. 如何在android的jni線程中實現回調

jni回調是指在c/c++代碼中調用java函數,當在c/c++的線程中執行回調函數時,會導致回調失敗。

其中一種在Android系統的解決方案是:

把c/c++中所有線程的創建,由pthread_create函數替換為由Java層的創建線程的函數AndroidRuntime::createJavaThread。

假設有c++函數:

[cpp] view plain
void *thread_entry(void *args)
{
while(1)
{
printf("thread running...\n");
sleep(1);
}

}

void init()
{
pthread_t thread;
pthread_create(&thread,NULL,thread_entry,(void *)NULL);
}

init()函數創建一個線程,需要在該線程中調用java類Test的回調函數Receive:

[cpp] view plain
public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback:" + msg;
Log.d("Test", msg);
}

首先在c++中定義回調函數指針:

[cpp] view plain
//test.h
#include <pthread.h>
//function type for receiving data from native
typedef void (*ReceiveCallback)(unsigned char *buf, int len);

/** Callback for creating a thread that can call into the Java framework code.
* This must be used to create any threads that report events up to the framework.
*/
typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg);

typedef struct{
ReceiveCallback recv_cb;
CreateThreadCallback create_thread_cb;
}Callback;

再修改c++中的init和thread_entry函數:

[cpp] view plain
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/wait.h>
#include <unistd.h>
#include "test.h"

void *thread_entry(void *args)
{
char *str = "i'm happy now";
Callback cb = NULL;
int len;
if(args != NULL){
cb = (Callback *)args;
}

len = strlen(str);
while(1)
{
printf("thread running...\n");
//invoke callback method to java
if(cb != NULL && cb->recv_cb != NULL){
cb->recv_cb((unsigned char*)str, len);
}
sleep(1);
}

}

void init(Callback *cb)
{
pthread_t thread;
//pthread_create(&thread,NULL,thread_entry,(void *)NULL);
if(cb != NULL && cb->create_thread_cb != NULL)
{
cb->create_thread_cb("thread",thread_entry,(void *)cb);
}
}

然後在jni中實現回調函數,以及其他實現:

[cpp] view plain
//jni_test.c
#include <stdlib.h>
#include <malloc.h>
#include <jni.h>
#include <JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"

#include "test.h"
#define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"

using namespace android;

static jobject mCallbacksObj = NULL;
static jmethodID method_receive;

static void (JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
LOGE("An exception was thrown by callback '%s'.", methodName);
LOGE_EX(env);
env->ExceptionClear();
}
}

static void receive_callback(unsigned char *buf, int len)
{
int i;
JNIEnv* env = AndroidRuntime::getJNIEnv();
jcharArray array = env->NewCharArray(len);
jchar *pArray ;

if(array == NULL){
LOGE("receive_callback: NewCharArray error.");
return;
}

pArray = (jchar*)calloc(len, sizeof(jchar));
if(pArray == NULL){
LOGE("receive_callback: calloc error.");
return;
}

// buffer to jchar array
for(i = 0; i < len; i++)
{
*(pArray + i) = *(buf + i);
}
// buffer to jcharArray
env->SetCharArrayRegion(array,0,len,pArray);
//invoke java callback method
env->CallVoidMethod(mCallbacksObj, method_receive,array,len);
//release resource
env->DeleteLocalRef(array);
free(pArray);
pArray = NULL;

(env, __FUNCTION__);
}

static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
}

static Callback mCallbacks = {
receive_callback,
create_thread_callback
};

static void jni_class_init_native
(JNIEnv* env, jclass clazz)
{
method_receive = env->GetMethodID(clazz, "Receive", "([CI)V");
}

static int jni_init
(JNIEnv *env, jobject obj)
{

if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);

return init(&mCallbacks);
}

static const JNINativeMethod gMethods[] = {
{ "class_init_native", "()V", (void *)jni_class_init_native },
{ "native_init", "()I", (void *)jni_init },
};

static int registerMethods(JNIEnv* env) {

const char* const kClassName = RADIO_PROVIDER_CLASS_NAME;
jclass clazz;
/* look up the class */
clazz = env->FindClass(kClassName);
if (clazz == NULL) {
LOGE("Can't find class %s/n", kClassName);
return -1;
}
/* register all the methods */
if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)
{
LOGE("Failed registering methods for %s/n", kClassName);
return -1;
}
/* fill out the rest of the ID cache */
return 0;
}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
LOGI("Radio JNI_OnLoad");
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed/n");
goto fail;
}

if(env == NULL){
goto fail;
}
if (registerMethods(env) != 0) {
LOGE("ERROR: PlatformLibrary native registration failed/n");
goto fail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
fail:
return result;
}

jni的Android.mk文件中共享庫設置為:

[cpp] view plain
LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

最後再實現Java中的Test類:

[java] view plain
//com.tonny.Test.java

public class Test {

static{
try {
System.loadLibrary("test");
class_init_native();

} catch(UnsatisfiedLinkError ule){
System.err.println("WARNING: Could not load library libtest.so!");
}

}

public int initialize() {
return native_radio_init();
}

public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback" + msg;
Log.d("Test", msg);
}

protected static native void class_init_native();

protected native int native_init();

}

G. android使用jni開發,能不能使用信號的

可以。實現JNI原生函數源文件:

新建com_lucyfyr_HelloWorld.c文件:

#include <jni.h>
#define LOG_TAG "HelloWorld"
#include <utils/Log.h>
/* Native interface, it will be call in java code */
JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI(JNIEnv *env, jobject obj,jstring inputStr)
{
LOGI("fresne Hello World From libhelloworld.so!");
// 從 instring 字元串取得指向字元串 UTF 編碼的指針
const char *str =
(const char *)(*env)->GetStringUTFChars( env,inputStr, JNI_FALSE );
LOGI("fresne--->%s",(const char *)str);
// 通知虛擬機本地代碼不再需要通過 str 訪問 Java 字元串。
(*env)->ReleaseStringUTFChars(env, inputStr, (const char *)str );
return (*env)->NewStringUTF(env, "Hello World! I am Native interface");
}
/* This function will be call when the library first be load.
* You can do some init in the libray. return which version jni it support.
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
void *venv;
LOGI("fresne----->JNI_OnLoad!");
if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
LOGE("fresne--->ERROR: GetEnv failed");
return -1;
}return JNI_VERSION_1_4;
}

OnLoadJava_com_lucyfyr_HelloWorld_printJNI

函數裡面做一些log輸出 注意JNI中的log輸出的不同。

JNI_OnLoad函數JNI規范定義的,當共享庫第一次被載入的時候會被回調,

這個函數裡面可以進行一些初始化工作,比如注冊函數映射表,緩存一些變數等,

最後返回當前環境所支持的JNI環境。本例只是簡單的返回當前JNI環境。

H. 如何在Android中使用匯編語言

由於Android環境非常復雜,框架都是用Java,因此要使用C/C++都需要做很多配置,使用匯編的話需要做更多的工作。
我這邊使用的是最新的Android4.0的開發工具,NDK也是最新支持4.0的。這個NDK與老版本的有一些比較明顯的不同。
由於我用的是Mac OS X,因此配置起來比瘟抖死上的要容易許多,你不需要再裝些雜七雜八的第三方工具,直接可以使用你下載好的NDK。
首先,設置目標路徑——在你的Terminal中進入NDK的根目錄,隨後打NDK_PROJECT_PATH="<你要編譯的項目路徑>"。回車,再輸入export NDK_PROJECT_PATH
回車。
這里要注意的是NDK_PROJECT_PATH=後面的路徑需要加引號,否則無效。
由於NDK默認支持的默認編譯選項僅支持ARMv5到ARMv5TE架構,因此如果要使用比較高級的特性的話有兩種方法:
1、你有辦法將TARGET_ARCH_ABI的值變為armeabi-v7a,俺自己試了一下,木有成功。因此可以使用第二種方法,更簡單便捷:
2、在你的NDK目錄下,找到toolchains,然後找到arm-linux-androideabi-x.y.z目錄,在進去可以發現setup.mk文件。找到-march=armv7-a,將上面的神馬#ifdef都去掉,下面的#endif也都刪了。這樣就能確保編譯器使用ARMv7A來編譯。
完成上述操作之後我們就可以先用最簡單的方式來寫匯編了,即內聯匯編——

static int my_thumb(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"bx lr");

return mmy;
}

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_thumb(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}


上述代碼其實就是基於NDK自帶的hello-jni項目修改的。最後用ndk-build可以成功編譯。

上面一段代碼是編譯器默認的使用Thumb/Thumb-2編譯的,因此我裡面寫的內聯匯編的指令都是Thumb代碼。
我們下面將講述一下如何使用ARM代碼並使用NEON指令集。
首先,在你的Android.mk中修改LOCAL_SRC_FILES,要將源文件名後面添加.neon後綴,比如LOCAL_SRC_FILES := hello-jni.c改成LOCAL_SRC_FILES := hello-jni.c.neon。
這里要注意的是你真正的源文件名不要修改,就修改LOCAL_SRC_FILES這個符號的值即可。
然後我們再添加新的變數,來指示ARM GCC使用ARM指令集來編譯——LOCAL_ARM_MODE := arm
這樣就OK了。我們修改一下代碼:

static int my_arm(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"vp.32 q0, r0 \t\n"
"bx lr");

return mmy;
}

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_arm(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}


使用ndk-build後能正常通過編譯。
最後再上個最最高端的。直接寫匯編文件。NDK帶有GAS工具,因此按常理,完全可以寫匯編文件。一般匯編文件的後綴名為.s,因此我們創建一個xxx.s文件即可。
然後我這邊創建一個叫hey.s。在Android.mk中將這個文件添加上:LOCAL_SRC_FILES += hey.s.neon
我們這里看到,為了能在匯編文件中使用NEON指令集,我們在這里也把.neon後綴添加上。匯編器的makefile也認這個標識。
我們編輯hey.s文件:

.text
.align 4
.arm
.globl my_real_arm
my_real_arm:
add r0, r0, #256
vmov q0, q1
vp.32 q0, r0
bx lr
這里要注意的是,在Apple的匯編器中,函數名要加前綴下劃線,而NDK中提供的匯編器則不需要。
我們修改一下hello-jni.c,把這函數調進去:

extern void my_real_arm(int i);

static int my_arm(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"vp.32 q0, r0 \t\n"
"bx lr");

return mmy;
}
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_real_arm(0);
my_arm(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
當然,我們為了確保編譯器能夠正確地將ARM和Thumb指令集做混合連接,我們可以在剛才的setup.mk中強制在TARGET_CFLAGS標志里加上-mthumb-interwork
在Windows操作系統中試驗,終於發現,只要將Application.mk中的APP_ABI中的標志,將armeabi去掉,僅留下armeabi-v7a就能順利使用neon了。這樣不需要修改setup.mk,也不需要將Sample中的那個標志判斷去掉,非常方便。
下面列一下可用的Android.mk編譯配置文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := HelloNeon
LOCAL_SRC_FILES := helloneon.c
LOCAL_ARM_MODE := arm
TARGET_CFLAGS += -mthumb-interwork
TARGET_CFLAGS += -std=gnu11
TARGET_CFLAGS += -O3
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS := -DHAVE_NEON=1
LOCAL_SRC_FILES += neontest.s.neon
LOCAL_ARM_NEON := true
endif
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
$(call import-mole,cpufeatures)
在使用JNI時,只需要在你當前項目工程目錄中添加jni文件夾,然後在裡面根據Sample中所提供的文件布局來做即可。當你用ndk-build(Windows下要在cygwin控制台中用ndk-build.cmd)來編譯時, 如果構建成功,則會在libs文件夾內生成一個libXXX.so。然後用Eclipse ADT重新打開你的項目工程,就會發現jni文件目錄以及生成好的so文件都會在你的工程文件目錄中展現出來。當然,你後面也能直接在Eclipse IDE下編輯.s匯編文件,這樣就更容易閱讀了。
最後,在Android匯編器中如果要注釋某條語句,那麼必須使用C89/90中的注釋符——/* ... */
用分號以及後來C++98中所引入的//形式都不管用。
在最新的NDK版本android-ndk-r8d中加入了ARM-Linux GCC4.7以及當前大紅大紫的LLVM Clang3.1。不過由於LLVM Clang3.1的很多編譯選項與GCC有不少區別,因此在使用Clang3.1的時候需要自己去配置相應的編譯選項。這個版本的NDK默認的編譯器工具鏈使用的是GCC4.6版本。如果要使用GCC4.7,那麼可以在Application.mk文件中添加NDK_TOOLCHAIN_VERSION=4.7;如果要使用Clang3.1,那麼可以在Application.mk中添加NDK_TOOLCHAIN_VERSION=clang3.1。下面給出一個合法的Application.mk的內容:

# Build with LLVM Clang3.1
#NDK_TOOLCHAIN_VERSION=clang3.1

# Build with ARM-Linux GCC4.7
NDK_TOOLCHAIN_VERSION=4.7

# Build only ARMv7-A machine code.
APP_ABI := armeabi-v7a

I. android中envinment中的每個方法的意思

點到這個類里看就行了

J. android源碼里 c調java error: undefined reference to 'JNI_CreateJavaVM'求助

android 裡面的java調用c,主要是通過ndk組件來實現的,env和vm都是系統創建好了的,可以直接調用的,看的出來樓主應該是ndk方面的初學者,對jni,ndk這些東西的關系應該沒有弄清楚,如果僅僅是一個java和c互掉的話,可以看我的帖子「ndk java 和 c 互掉」:
http://jingyan..com/article/f54ae2fcde72be1e92b84916.html
帖子集文檔,截圖,視頻於一體,涉及java調用c和c調用java兩部分,
由於感覺你是ndk的初學者,所以有時間的話,建議你看看我總結的帖子"android ndk資源匯總":
http://tieba..com/p/3439627347
希望對你有用,我是ndk吧吧主,有問題可以ndk吧留言,謝謝!

閱讀全文

與androidenv相關的資料

熱點內容
手機程序加密有什麼作用 瀏覽:178
求黑馬程序員python教程 瀏覽:528
androidmvvm優缺點 瀏覽:894
unix下編譯庫文件 瀏覽:633
程序員的u盤 瀏覽:237
android根據經緯度獲取城市 瀏覽:564
python使用解釋器還是編譯器 瀏覽:358
以下關於有加密演算法及密鑰描述 瀏覽:219
linuxgethostname 瀏覽:416
程序員多數有對象 瀏覽:131
單片機延時程序計算 瀏覽:444
編譯原理語法翻譯 瀏覽:504
pr編譯出錯渲染存在偏移 瀏覽:262
如何製作自家的app 瀏覽:199
推薦一個解壓軟體rar解壓幫手 瀏覽:210
wd文檔加密器 瀏覽:748
伺服器上傳壓縮包一般是什麼格式 瀏覽:333
發送加密文件密碼幾位數 瀏覽:160
樹洞app怎麼樣 瀏覽:175
vivo編譯時間可以改么 瀏覽:150