IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> AndroidJNI 基础使用 -> 正文阅读

[移动开发]AndroidJNI 基础使用

本文主要说明了在Android应用程序中,怎么使用jni交互.
包括:回调接口,获取对象,不同线程汇总怎么使用JNIEnv *env等实例.

简单的理解一下概念

在jni中,用jfieldID和jmethodID来表示Java类的成员变量和成员函数.

比如:我们的jni侧要获取java对象中的某个String. java代码精简如下:

class InstanceFieldAccess { 
     private String text; 
  
     private native void accessField(); 
     public static void main(String args[]) { 
         InstanceFieldAccess ifa = new InstanceFieldAccess(); 
         ifa.text = "abcdefg"; 
         ifa.accessField(); 
         System.out.println("Java output"); 
         System.out.println("  ifa.text = \"" + ifa.text + "\""); 
     } 
     static { 
         System.loadLibrary("InstanceFieldAccess"); 
     } 
 } 

c++代码精简如下:

JNIEXPORT void JNICALL  Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj) 
 { 
     jfieldID fid;   //字段id,在jni中对应着java的类成员变量
     jstring jstr;   //jstring类型,对应的java中的String
     const char *str; 
  
     //第一步,我们获取类对象,因为是非静态方法所以是object
     jclass cls = (*env)->GetObjectClass(env, obj); 
     printf("C output:\n"); 
  
     //第二步,通过jni函数表,获取类对象里面的成员变量.
     fid = (*env)->GetFieldID(env, cls, "text", "Ljava/lang/String;"); 
     if (fid == NULL) { 
         return; //如果是空的,那就是没有找到,返回. 
     } 
     
     //第三步,找到了字段id,那么就开始读取值.因为字符串是个特殊的对象,所以这里使用GetObjectField读取.
     jstr = (*env)->GetObjectField(env, obj, fid); 
    //第四步,读取到了String值因为 Java 默认使用 Unicode 编码,而 C/C++ 默认使用 UTF 编码,所以在本地代码中操作字符串的时候,必
	//须使用合适的 JNI 函数把 jstring 转换成 C 风格的字符串
     str = (*env)->GetStringUTFChars(env, jstr, NULL); 
     if (str == NULL) { 
         return; //调用完 GetStringUTFChars 之后不要忘记安全检查,因为 JVM 需要为新诞生的字符串分配内存空间,当内存
				//空间不够分配的时候,会导致调用失败,失败后 GetStringUTFChars 会返回 NULL,并抛出一个OutOfMemoryError 异常
     } 
     printf("  c.s = \"%s\"\n", str); 
    //在调用 GetStringUTFChars 函数从 JVM 内部获取一个字符串之后,JVM 内部会分配一块新的内存,用于存
	//储源字符串的拷贝,以便本地代码访问和修改。即然有内存分配,用完之后就可以马上释放了.
     (*env)->ReleaseStringUTFChars(env, jstr, str); 
  
     //通过调用 NewStringUTF 函数,会构建一个新的 java.lang.String 字符串对象。这个新创建的字符串会自动转换成Java支持的Unicode编码 
     jstr = (*env)->NewStringUTF(env, "123"); 
     if (jstr == NULL) { 
         return; /* out of memory */ 
     } 
    //通过jni函数表,给java对象的变量赋值
     (*env)->SetObjectField(env, obj, fid, jstr); 
}
//打印
/**
C output:
   c.s = "abc"
Java output:
   ifa.text = "123"
*/

Android的java文件怎么写

public interface IWifiStaServiceService {
    // methods
    public ActivateOutput activate();
    public AddApOutput addAp(WifiConfiguration wifiConfiguration);
    public ConnectOutput connect(WifiConfiguration wifiConfiguration);
    public DeactivateOutput deactivate();
    public DisconnectOutput disconnect();
    public ForgetOutput forget(WifiApID wifiApID);
    public GetApListOutput getApList();
    public GetConfiguredApListOutput getConfiguredApList();
    public GetConnectedApOutput getConnectedAp();
    public GetConnectionInfoOutput getConnectionInfo();
    public GetMacAddressOutput getMacAddress();
    public IsActivatedOutput isActivated();
    public ScanOutput scan();
    public UpdateApOutput updateAp(WifiConfiguration wifiConfiguration);

    // fields
}

public class WifiStaServiceServiceStub {
    public static final String LOG_TAG = "WifiStaServiceServiceStub";

    public static final String INSTANCE_NAME_1 = "WifiStaService_Provider/WifiStaService_ProviderRootSwc/WifiStaService1";

    private static final int METHOD_ACTIVATE = 0;
    private static final int METHOD_ADDAP = 1;
    private static final int METHOD_CONNECT = 2;
    private static final int METHOD_DEACTIVATE = 3;
    private static final int METHOD_DISCONNECT = 4;
    private static final int METHOD_FORGET = 5;
    private static final int METHOD_GETAPLIST = 6;
    private static final int METHOD_GETCONFIGUREDAPLIST = 7;
    private static final int METHOD_GETCONNECTEDAP = 8;
    private static final int METHOD_GETCONNECTIONINFO = 9;
    private static final int METHOD_GETMACADDRESS = 10;
    private static final int METHOD_ISACTIVATED = 11;
    private static final int METHOD_SCAN = 12;
    private static final int METHOD_UPDATEAP = 13;

    private static IWifiStaServiceService mService;
	//我们这里定义的都是静态类型的native方法,注意cpp里面对应的头文件
    private static native void native_init(String ap_env);
    private static native void native_setup(Object object, String instance);
    private static native void native_finalize();
    private static native void native_sendService();
    private static native void native_stopSendService();

    private static native void native_notifyRssiChanged(byte[] data);
    private static native void native_notifyScanFinished(byte[] data);
    private static native void native_notifyStaConnChanged(byte[] data);
    private static native void native_notifyStationChanged(byte[] data);

    static {
        try {
            System.loadLibrary("wifistaservice");
            Log.d(LOG_TAG, "load wifistaservice");
        } catch (Exception ex) {
            Log.e(LOG_TAG, "System.loadLibrary Exception " + ex);
        } catch (Error err) {
            Log.e(LOG_TAG, "System.loadLibrary Error " + err);
        }
    }
	//构造方法里面调用了2个native方法
    public WifiStaServiceServiceStub(IWifiStaServiceService service, String instance, String ap_env) {
        Log.d(LOG_TAG, "new WifiStaServiceServiceStub");
        native_init(ap_env);//参数只传递了一个String
        mService = service;
        native_setup(new WeakReference<WifiStaServiceServiceStub>(this), instance);//参数传递了一个软引用的对象和一个String
    }

    protected void finalize() {
        native_finalize();
    }

    public void sendService() {
        native_sendService();
    }

    public void stopSendService() {
        native_stopSendService();
    }

    public void notifyRssiChanged(WifiAp rssiChanged) {
        Log.d(LOG_TAG, "native_notifyRssiChanged");
        native_notifyRssiChanged(rssiChanged.toByteArray());
    }

    public void notifyScanFinished(WifiApList scanFinished) {
        Log.d(LOG_TAG, "native_notifyScanFinished");
        native_notifyScanFinished(scanFinished.toByteArray());
    }

    public void notifyStaConnChanged(WifiAp staConnChanged) {
        Log.d(LOG_TAG, "native_notifyStaConnChanged");
        native_notifyStaConnChanged(staConnChanged.toByteArray());
    }

    public void notifyStationChanged(int stationChanged) {
        Log.d(LOG_TAG, "native_notifyStationChanged");
        WifiStaServiceProto.ProtoUint8 proto_stationChanged = new WifiStaServiceProto.ProtoUint8();
        proto_stationChanged.value = stationChanged;
        native_notifyStationChanged(proto_stationChanged.toByteArray(proto_stationChanged));
    }

    //静态的java方法,这个方法会在native侧调用.注意关注三个参数
    private static byte[] postEventFromNative(Object Control_ref, int what, byte[] obj) {
        //获取类对象
        final WifiStaServiceServiceStub serviceimpl = (WifiStaServiceServiceStub)((WeakReference)Control_ref).get();
		//因为是从jni那边从来的,也就验证了底层有没有拿到这个对象
        if (serviceimpl == null) {
            Log.e(LOG_TAG, "postEventFromNative error : service is null");
            return null;
        }

        Log.d(LOG_TAG, "postEventFromNative what= " + what + " obj= " + obj);
        switch (what) {
        case METHOD_ACTIVATE:
            ActivateOutput ret_activate = mService.activate();
            if (ret_activate != null) {
                return ret_activate.toByteArray();
            }
            break;
        case METHOD_ADDAP:
            if (obj != null) {
                try {
                    WifiStaServiceProto.AddApInput in_addAp = WifiStaServiceProto.AddApInput.parseFrom(obj);
                    AddApOutput ret_addAp = mService.addAp(WifiConfiguration.fromByteArray(WifiStaServiceProto.WifiConfiguration.toByteArray(in_addAp.wifiConfiguration)));
                    if (ret_addAp != null) {
                        Log.d(LOG_TAG, "AddApOutput is not null ");
                        return ret_addAp.toByteArray();
                    } else {
                        Log.d(LOG_TAG, "AddApOutput is null ");
                    }
                } catch (com.google.protobuf.nano.InvalidProtocolBufferNanoException e) {
                    Log.d(LOG_TAG, e.toString());
                }
            }
            break;
        case METHOD_CONNECT:
            if (obj != null) {
                try {
                    WifiStaServiceProto.ConnectInput in_connect = WifiStaServiceProto.ConnectInput.parseFrom(obj);
                    ConnectOutput ret_connect = mService.connect(WifiConfiguration.fromByteArray(WifiStaServiceProto.WifiConfiguration.toByteArray(in_connect.wifiConfiguration)));
                    if (ret_connect != null) {
                        Log.d(LOG_TAG, "ConnectOutput is not null ");
                        return ret_connect.toByteArray();
                    } else {
                        Log.d(LOG_TAG, "ConnectOutput is null ");
                    }
                } catch (com.google.protobuf.nano.InvalidProtocolBufferNanoException e) {
                    Log.d(LOG_TAG, e.toString());
                }
            }
            break;
        default:
            break;
        }

        return null;
    }
}

jni头文件的定义

头文件定义了java代码对应的native方法,以及一个回调类.主要是用来回调java侧代码的postEventFromNative方法.

#ifndef _Included_com_yf_soa_wifistaservice_WifiStaServiceNativeListener
#define _Included_com_yf_soa_wifistaservice_WifiStaServiceNativeListener
#include <jni.h>
#include "WifiStaServiceNativeListener.h"
#include "wifistaservice/wifistaservice_skeleton.h"
#ifdef __cplusplus
extern "C" {
#endif

namespace yf {
namespace soa {

struct fields_t {
    jfieldID context;
    jmethodID post_event;//方法 ID(因为一个类中会存在多个方法,需要一个唯一标识来确定调用类中的哪个方法)
};

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub 对应java代码的类对象包名
 * Method:    native_init                                         java类对象方法native名  
 * Signature: ()V                                                 方法和参数签名   
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1init
(JNIEnv *, jclass, jstring);

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_setup
 * Signature: (Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1setup
(JNIEnv *, jclass, jobject, jstring);

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_finalize
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1finalize
(JNIEnv *, jclass);

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_offerService
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1offerService
(JNIEnv *, jclass);

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_stopOfferService
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1stopOfferService
(JNIEnv *, jclass);

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_notifyRssiChanged
 * Signature: (Lcom/yf/soa/wifistaservice/WifiAp;)V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1notifyRssiChanged
(JNIEnv *, jclass, jbyteArray);

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_notifyScanFinished
 * Signature: (Lcom/yf/soa/wifistaservice/WifiApList;)V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1notifyScanFinished
(JNIEnv *, jclass, jbyteArray);

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_notifyStaConnChanged
 * Signature: (Lcom/yf/soa/wifistaservice/WifiAp;)V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1notifyStaConnChanged
(JNIEnv *, jclass, jbyteArray);

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_notifyStationChanged
 * Signature: (Lcom/yf/soa/wifistaservice/StationState_ref;)V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1notifyStationChanged
(JNIEnv *, jclass, jbyteArray);

class WifiStaServiceNativeListenerImpl: public WifiStaServiceNativeListener {
public:
    //参数包含jni指针,和2个object对象
    WifiStaServiceNativeListenerImpl(JNIEnv* env, jobject thiz, jobject weak_thiz);
    ~WifiStaServiceNativeListenerImpl();

    virtual void syncDetachCurrentThread();
    virtual jbyteArray notify(JNIEnv *env, int msg, const jbyteArray obj);//通知

private://定义两个全局对象
    jclass mClass;//从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
    jobject mObject;//类的实例
};

class WifiStaServiceNative : public yf::platform::WifiStaServiceSkeleton {
public:
    virtual ~WifiStaServiceNative();

    static WifiStaServiceNative& instantiate() {
        static WifiStaServiceNative elmn; 
        return elmn;
    }
    //注册listener对象
    virtual void registerListener(const std::shared_ptr<WifiStaServiceNativeListener> listener);
    virtual sovpap::core::Future<nm_wifistaservice::internal::methods::Activate::Output> Activate();
    virtual sovpap::core::Future<nm_wifistaservice::internal::methods::AddAp::Output> AddAp(const DataTypes::WifiConfiguration& wifiConfiguration);
    virtual sovpap::core::Future<nm_wifistaservice::internal::methods::Connect::Output> Connect(const DataTypes::WifiConfiguration& wifiConfiguration);
    void notifyRssiChanged(const DataTypes::WifiAp& rssiChanged);
    void notifyScanFinished(const DataTypes::WifiApList& scanFinished);
    void notifyStaConnChanged(const DataTypes::WifiAp& staConnChanged);
    void notifyStationChanged(const DataTypes::StationState_ref& stationChanged);


private:
    explicit WifiStaServiceNative();
    WifiStaServiceNative& operator = (const WifiStaServiceNative&)=delete;
    std::shared_ptr<WifiStaServiceNativeListener> m_listener;
    enum notifyType {
        METHOD_ACTIVATE,
        METHOD_ADDAP,
        METHOD_CONNECT
    };
};

}  // namespace soa
}  // namespace yf

#ifdef __cplusplus
}
#endif
#endif  // _Included_com_yf_soa_wifistaservice_WifiStaServiceNativeListener

看一下另一个回调函数的头文件

#ifndef WIFISTASERVICENATIVELISTENER_H
#define WIFISTASERVICENATIVELISTENER_H
#include <jni.h>
using namespace  android;
#ifndef __cplusplus
#   error ERROR: This file requires C++ compilation (use a .cpp suffix)
#endif


namespace yf {
namespace soa {

class WifiStaServiceNativeListener
{
public:
    virtual void syncDetachCurrentThread() = 0;
    virtual jbyteArray notify(JNIEnv *env, int msg, const jbyteArray obj) = 0;
    virtual ~WifiStaServiceNativeListener(){};
};

}  // namespace soa
}  // namespace yf

#endif  // WIFISTASERVICENATIVELISTENER_H

再理解几个概念

JavaVM是虚拟机在JNI中的表示,一个JVM中只有一个JavaVM对象,这个对象是线程共享的。

通过JNIEnv我们可以获取一个Java虚拟机对象,其函数如下:

jint GetJavaVM(JNIEnv *env, JavaVM **vm);

  • vm:用来存放获得的虚拟机的指针的指针。
  • return:成功返回0,失败返回其他。

AttachCurrentThread 链接到虚拟机

JNIEnv指针仅在创建它的线程有效。如果我们需要在其他线程访问JVM,那么必须先调用AttachCurrentThread将当前线程与JVM进行关联,然后才能获得JNIEnv对象。当然,我们在必要时需要调用DetachCurrentThread来解除链接。

jint AttachCurrentThread(JavaVM* vm , JNIEnv** env , JavaVMAttachArgs* args);

  • vm:虚拟机对象指针。
  • env:用来保存得到的JNIEnv的指针。
  • args:链接参数,参数结构体如下所示。
  • return:链接成功返回0,连接失败返回其他。

仔细看看jni的实现文件

#include <jni.h>
#include <android/log.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
#include "WifiStaServiceServiceJni.h"
#include <WifiStaServiceDataTransfer.h>
#include "ara/core/promise.h"
#include "ara/core/initialization.h"

#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "WifiStaServiceServiceJni"

#ifdef __cplusplus
extern "C" {
#endif

namespace yf {
namespace soa {

std::string g_instance_name;
static fields_t fields;
static pthread_key_t sThreadKey;
static JavaVM* javaVM;
static android::Mutex sJNIEnvLock;

jobject g_WifiStaServiceServiceStubClass;

static JNIEnv *getJNIEnv() {
    android::Mutex::Autolock l(sJNIEnvLock);//加锁,防止多线程获取不同步
    ALOGD("[%s:%d][%s]", __FUNCTION__, __LINE__, __FILE__);
    if (javaVM == NULL) {
        ALOGE("[%s:%d][%s] Java VM is NULL", __FUNCTION__, __LINE__, __FILE__);
        return NULL;
    }
    JNIEnv *envnow = NULL;
    int status = javaVM->GetEnv((void **)&envnow, JNI_VERSION_1_6);
    ALOGD("[%s:%d][%s] GetEnv::status = [%d]", __FUNCTION__, __LINE__, __FILE__, status);
    if (status == JNI_EDETACHED) {
        if( 0 <= javaVM->AttachCurrentThread(&envnow, NULL)) {
            ALOGD("[%s:%d][%s] AttachCurrentThread::status = [%d]", __FUNCTION__, __LINE__, __FILE__, status);
            /**
             * use that key with pthread_setspecific to store JNIEnv in thead-local-storage.
             * In that, it'll be passed into your destructor as the argument.
             *
             */
            if (NULL == pthread_getspecific(sThreadKey)) {
                pthread_setspecific(sThreadKey, &envnow);
            }
        }
    }
    return envnow;
}

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_init
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1init
(JNIEnv * env, jclass clazz, jstring ap_env) {
    ALOGD("=================== JNI call native_init ========================");
	//从classpath路径下搜索ClassMethod这个类,并返回该类的Class对象
    jclass jcls = env->FindClass("com/yf/soa/wifistaservice/WifiStaServiceServiceStub");
    //调用 NewGlobalRef 基于局部引用创建,会阻GC回收所引用的对象。可以跨方法、跨线程使用。JVM不会自
	//动释放,必须调用DeleteGlobalRef手动释放。 (*env)->DeleteGlobalRef(env,g_cls_string)
    g_WifiStaServiceServiceStubClass = env->NewGlobalRef(jcls);
	//将方法id保存在结构体中的jmethodid中
    fields.post_event = env->GetStaticMethodID(jcls, "postEventFromNative", "(Ljava/lang/Object;I[B)[B");
    //获取全局的javavm
    env->GetJavaVM(&javaVM);
    if (fields.post_event == NULL) {
       ALOGD("JNI_native_init fields.post_event is null");
       return;
    }
    if (getenv("AA_CONFIG_FILES_PATH")) {
        ALOGD("env already setted, AA_CONFIG_FILES_PATH: %s", getenv("AA_CONFIG_FILES_PATH"));
    } else {
        if (ap_env) {
            const char *jap_env = env->GetStringUTFChars(ap_env, NULL);
            if (0 != setenv("AA_CONFIG_FILES_PATH", jap_env, 1)) {
                ALOGE("setenv error ");
            }
            if (!ara::core::Initialize().HasValue()) {
                ALOGE("ara::core::init error ");
                ara::core::Abort("ara::core::Initialize() failed for Service, calling abort...");
            }
        } else {
            ALOGE("native_init without ap env set up");
        }
    }
}

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_setup
 * Signature: (Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1setup
(JNIEnv *env, jclass clazz, jobject weak_this, jstring instance) {
    ALOGD("=================== JNI call native_setup ========================");
    //新建监听器对象
    std::shared_ptr<WifiStaServiceNativeListenerImpl> listener = std::make_shared<WifiStaServiceNativeListenerImpl>(env, clazz, weak_this);
    ALOGD("=================== JNI call native_setup new WifiStaServiceNativeListenerImpl ok========================");
    g_instance_name = std::string(env->GetStringUTFChars(instance, NULL));
    //注册监听回调,这样就能收到其他库的回调监听了.
    WifiStaServiceNative::instantiate().registerListener(listener);
}

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_finalize
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1finalize
(JNIEnv * env, jclass clazz) {
    ALOGD("=================== JNI call native_finalize ========================");
}

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_offerService
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1sendService
(JNIEnv *, jclass) {
    ALOGD("=================== JNI call native_offerService ========================");
    WifiStaServiceNative::instantiate().OfferService();
}

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_stopOfferService
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1stopSendService
(JNIEnv *, jclass) {
    ALOGD("=================== JNI call native_stopOfferService ========================");
    WifiStaServiceNative::instantiate().StopOfferService();
}

/*
 * Class:     com_yf_soa_wifistaservice_WifiStaServiceServiceStub
 * Method:    native_notifyRssiChanged
 * Signature: (Lcom/yf/soa/wifistaservice/WifiAp;)V
 * 通知wifi信号的方法,java侧会将数据传到jni侧.
 */
JNIEXPORT void JNICALL Java_com_yf_soa_wifistaservice_WifiStaServiceServiceStub_native_1notifyRssiChanged
(JNIEnv *env, jclass clazz, jbyteArray jrssichanged) {
    ALOGD("=================== JNI call native_notifyRssiChanged ========================");
    DataTypes::WifiAp arxml_rssiChanged;
    DataTransfer::WifiAp transfer_rssichanged;
    ::com::yf::soa::wifistaservice::WifiAp proto_rssichanged;
    if (jrssichanged) {
        //下面的逻辑就是通过byte数组,然后通过google的protobuf转换传给其他的需要者
        jbyte *data = env->GetByteArrayElements(jrssichanged, 0);
        int data_len = env->GetArrayLength(jrssichanged);
        proto_rssichanged.ParseFromArray(data, data_len);
        env->ReleaseByteArrayElements(jrssichanged, data, 0);
        transfer_rssichanged.fromProto(proto_rssichanged).toArxml(arxml_rssiChanged);
    }

    WifiStaServiceNative::instantiate().notifyRssiChanged(arxml_rssiChanged);
}
//实现WifiStaServiceNativeListenerImpl类,构造函数
WifiStaServiceNativeListenerImpl::WifiStaServiceNativeListenerImpl(JNIEnv* env, jobject thiz, jobject weak_thiz) {
    ALOGD("WifiStaServiceNativeListenerImpl::WifiStaServiceNativeListenerImpl");
    //这个地方我们看到是一个本地的jclass,主要是用来判断是否为空.由上面的native_setup函数传参
    //thiz是代表静态的native_setup方法.weak_thiz代表java侧的接口IWifiStaServiceService
    jclass clazz = env->GetObjectClass(thiz);

    if (clazz == NULL) {
        return;
    }
    //获取在init函数保存的全局passclassload 路径对象
    mClass = (jclass)g_WifiStaServiceServiceStubClass;
    //保存全局的java侧对象的类实例
    mObject  = env->NewGlobalRef(weak_thiz);
}
//析构函数做一些释放的操作,比如我们保存的一些全局引用
WifiStaServiceNativeListenerImpl::~WifiStaServiceNativeListenerImpl() {
    ALOGD("WifiStaServiceNativeListenerImpl::~WifiStaServiceNativeListenerImpl");
    JNIEnv *env = getJNIEnv();
    if (NULL == env) {
        return;
    }
    env->DeleteGlobalRef(mObject);
    env->DeleteGlobalRef(mClass);

    syncDetachCurrentThread();
}
//注册回调后,在notify会收到其他c++程序发来的消息,这个消息我们需要转发到java侧.看看怎么做.
jbyteArray WifiStaServiceNativeListenerImpl::notify(JNIEnv* env, int msg, const jbyteArray obj) {
    ALOGD("WifiStaServiceNativeListenerImpl::notify");
    //具体的数据,这里是字节数组
    jbyteArray retobj = nullptr;
    if (NULL == env) {
        ALOGW("ERROR: JNIEnv is NULL LINE");
        return retobj;
    }
	//如果说在native_init里面保存的java方法postEventFromNative id号是空的,那就是有问题,直接return 
    if (NULL == fields.post_event) {
        ALOGW("notify fields.post_event is NULL");
        return retobj;
    }
    ALOGW("notify msg %d", msg);
    //没有问题的话,就调用java的postEventFromNative方法进行回调.首先Java postEventFromNative方法是个静态static的,
    //所以调用CallStaticObjectMethod
    //1.mClass是代表这个java的类对象路径com/yf/soa/wifistaservice/WifiStaServiceServiceStub
    //2.fields.post_event是保存着对象WifiStaServiceServiceStub里面postEventFromNative对象id
    //3.mObject是实例化WifiStaServiceServiceStub类
    //4.msg是消息type
    //5.obj每个消息type都会有自己的数据
    //6.java侧通过postEventFromNative方法返回的数据,jni侧获取到
    retobj = (jbyteArray)env->CallStaticObjectMethod(mClass, fields.post_event, mObject, msg, obj);

    return retobj;
}

void WifiStaServiceNativeListenerImpl::syncDetachCurrentThread() {
    // ALOGD("syncDetachCurrentThread");
    // android::Mutex::Autolock l(sJNIEnvLock);
    // javaVM->DetachCurrentThread();
}

WifiStaServiceNative::WifiStaServiceNative()
: yf::platform::WifiStaServiceSkeleton(ara::core::InstanceSpecifier(ara::core::StringView(g_instance_name.c_str(), g_instance_name.size())))
{
    ALOGD("WifiStaServiceNative::WifiStaServiceNative");
}

WifiStaServiceNative::~WifiStaServiceNative() {
    ALOGD("WifiStaServiceNative::~WifiStaServiceNative");
}

void WifiStaServiceNative::registerListener(const std::shared_ptr<WifiStaServiceNativeListener> listener) {
    ALOGD("WifiStaServiceNative::registerListener");
    m_listener = listener;
}

sovpap::core::Future<nm_wifistaservice::internal::methods::Activate::Output> WifiStaServiceNative::Activate() {
    ara::core::Promise<nm_wifistaservice::internal::methods::Activate::Output> prom;
    DataTransfer::ActivateOutput dataTransferOutput;
    ::com::yf::soa::wifistaservice::ActivateOutput protoOutput;
    nm_wifistaservice::internal::methods::Activate::Output arxmlOutput;
    //获取jni函数表,可用于多线程
    JNIEnv *env = getJNIEnv();
	//不同的type,调用notify函数获取java侧返回的数据
    jbyteArray jOutput = m_listener->notify(env, METHOD_ACTIVATE, nullptr);

    if (jOutput) {
        jbyte *data = env->GetByteArrayElements(jOutput, 0);
        int data_len = env->GetArrayLength(jOutput);
        protoOutput.ParseFromArray(data, data_len);
        env->ReleaseByteArrayElements(jOutput, data, 0);
        dataTransferOutput.fromProto(protoOutput).toArxml(arxmlOutput);
    } else {
        ALOGE("%s notify ret obj is null", __FUNCTION__);
    }
    m_listener->syncDetachCurrentThread();
    prom.set_value(std::move(arxmlOutput));
    return prom.get_future();
}

sovpap::core::Future<nm_wifistaservice::internal::methods::AddAp::Output> WifiStaServiceNative::AddAp(const DataTypes::WifiConfiguration& wifiConfiguration) {
    ara::core::Promise<nm_wifistaservice::internal::methods::AddAp::Output> prom;
    DataTransfer::AddApInput dataTransferInput;
    DataTransfer::AddApOutput dataTransferOutput;
    ::com::yf::soa::wifistaservice::AddApInput protoInput;
    ::com::yf::soa::wifistaservice::AddApOutput protoOutput;
    nm_wifistaservice::internal::methods::AddAp::Input arxmlInput;
    nm_wifistaservice::internal::methods::AddAp::Output arxmlOutput;
    JNIEnv *env = getJNIEnv();
    arxmlInput.WifiConfiguration = wifiConfiguration;
    dataTransferInput.fromArxml(arxmlInput).toProto(protoInput);
    jbyteArray jInput = env->NewByteArray(protoInput.ByteSize());
    jbyte *pInput = env->GetByteArrayElements(jInput, NULL);
    protoInput.SerializeToArray(pInput, protoInput.ByteSize());
    env->ReleaseByteArrayElements(jInput, pInput, 0);

    jbyteArray jOutput = m_listener->notify(env, METHOD_ADDAP, jInput);

    if (jOutput) {
        jbyte *data = env->GetByteArrayElements(jOutput, 0);
        int data_len = env->GetArrayLength(jOutput);
        protoOutput.ParseFromArray(data, data_len);
        env->ReleaseByteArrayElements(jOutput, data, 0);
        dataTransferOutput.fromProto(protoOutput).toArxml(arxmlOutput);
    } else {
        ALOGE("%s notify ret obj is null", __FUNCTION__);
    }
    m_listener->syncDetachCurrentThread();
    prom.set_value(std::move(arxmlOutput));
    return prom.get_future();
}

void WifiStaServiceNative::notifyRssiChanged(const DataTypes::WifiAp& _rssiChanged) {
    RssiChanged.Send(_rssiChanged);
}

void WifiStaServiceNative::notifyScanFinished(const DataTypes::WifiApList& _scanFinished) {
    ScanFinished.Send(_scanFinished);
}

void WifiStaServiceNative::notifyStaConnChanged(const DataTypes::WifiAp& _staConnChanged) {
    StaConnChanged.Send(_staConnChanged);
}

void WifiStaServiceNative::notifyStationChanged(const DataTypes::StationState_ref& _stationChanged) {
    StationChanged.Send(_stationChanged);
}

}  // namespace soa
}  // namespace yf
#ifdef __cplusplus
}
#endif

总结一下

访问和修改实例变量操作步聚:

? 调用 GetObjectClass 函数获取实例对象的 Class 引用
? 调用 GetFieldID 函数获取 Class 引用中某个实例变量的 ID
? 调用 GetXXXField 函数获取变量的值,需要传入实例变量所属对象和变量 ID
? 调用 SetXXXField 函数修改变量的值,需要传入实例变量所属对象、变量 ID 和变量的值

访问和修改静态变量操作步聚:

? 调用 FindClass 函数获取类的 Class 引用
? 调用 GetStaticFieldID 函数获取 Class 引用中某个静态变量 ID
? 调用 GetStaticXXXField 函数获取静态变量的值,需要传入变量所属 Class 的引用和变量 ID
? 调用 SetStaticXXXField 函数设置静态变量的值,需要传入变量所属 Class 的引用、变量 ID和变量的

访问和修改实例变量操作步聚:

? 调用 GetObjectClass 函数获取实例对象的 Class 引用
? 调用 GetFieldID 函数获取 Class 引用中某个实例变量的 ID
? 调用 GetXXXField 函数获取变量的值,需要传入实例变量所属对象和变量 ID
? 调用 SetXXXField 函数修改变量的值,需要传入实例变量所属对象、变量 ID 和变量的值

访问和修改静态变量操作步聚:

? 调用 FindClass 函数获取类的 Class 引用
? 调用 GetStaticFieldID 函数获取 Class 引用中某个静态变量 ID
? 调用 GetStaticXXXField 函数获取静态变量的值,需要传入变量所属 Class 的引用和变量 ID
? 调用 SetStaticXXXField 函数设置静态变量的值,需要传入变量所属 Class 的引用、变量 ID和变量的

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-12 13:16:58  更:2021-09-12 13:18:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:07:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码