栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

一,Ndk开发【基础】

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一,Ndk开发【基础】

1.1-基本概念 Android SDK【Java层】

  Android SDK全称是:Android Software Development Kit【Android 软件开发工具包】,Android SDK主要为开发者提供Java层的API调用以及开发过程中所需要的一些构建工具和其它工具;所以说你可以把Android SDK理解成就是Android应用的Java层开发【执行环境:虚拟机】

Android NDK【C/C++层】

  Android NDK全称是:Android Native Development Kit【Android 本地开发工具包】,Android NDK主要为开发者提供C/C++层的API接口以及开发过程中所需要的一些构建工具和其它工具;所以说你可以把Android NDK理解成就是Android应用的C/C++底层库开发【执行环境:操作系统】

Android JNI【Java-桥梁-C/C++】

  Android JNI全称:Android native interface【Android 本地接口】,Android JNI主要是为上层Java/Kotlin与本地C/C++ 提供互通互调机制,简单点说: Java代码中可以调用Native C/C++代码,Native C/C++代码可以调用上层Java代码;所以说Android JNI就是连接上层Java与本地C/C++互通互调的一个桥梁和机制!

CPU架构: 指令派系:
  • 精简指令集【RISC】
    Intel,AMD
  • 复杂指令集【CISC】
    IBM,ARM
常见架构:

x86,x86-64/x64
arm64-v8a,armeabi-v7a【32位】,armeabi【32位】

API-ABI:
  • API
    API【Application Program Interface 应用程序接口】其实就是一套预先定义的,无需了解内部的实现机理和细节,与硬件系统无关的一套调用接口!
  • ABI
    ABI【Application Binary Interface 应用程序二进制接口】定义了一套二进制规则,它允许在所有兼容该ABI编译的目标代码的操作系统和硬件系统中,无须改动即可运行,从这里我们就看出,ABI其实就是一套约束底层,系统,硬件,编译规则的一套二进制接口!
    【EABI : 是 arm 对于 ABI规范的较新(2005年)的实现】
1.2-环境配置
  • 安装Android Studio
    https://developer.android.google.cn/studio 下载地址
    https://developer.android.google.cn/studio/intro/ 帮助文档

  • 创建NDK项目

  • 配置NDK

    手动配置: https://developer.android.google.cn/ndk/downloads

1.3-常用配置 配置支持ABI

大厂适配ABI文章:https://mp.weixin.qq.com/s/jnZpgaRFQT5ULk9tHWMAGg

module模块: build.gradle

    defaultConfig {
        applicationId "com.example.ndkdemo"
        minSdk 21
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ''
//                方法1:externalNativeBuild-》cmake:
//                abiFilters 'armeabi-v7a'
            }
        }
//        方法2:defaultConfig-》ndk:
        ndk{
            abiFilters 'armeabi-v7a','arm64-v8a','x86'
        }
    }
配置输出目录

默认输出目录:

#不同Android Studio版本有的生效有的不生效
#方式1:
#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI})
#方式2:
#set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI})
1.4-JNI基本语法

https://www.kancloud.cn/owenoranba/jni/120478 中文JNI学习参考文档

声明本地方法【Java层:Native方法】
//Native方法-》目的-》调用本地C/C++方法!
public native String stringFromJNI();
实现本地方法【C++层:C++方法】
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_ndkdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject ) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
本地方法说明【Java层Native声明】
  • 静态注册JNI
    Java层:Native声明-》对应一种固定格式-》C++层:C++方法【Java_包名_Java类名_方法名】
  • 动态注册JNI
JNI相关元素【JavaVM-JNIEnv-jobject-jclass】 JavaVM

  JavaVM是虚拟机在JNI层的表示,一个进程只有JVM,所有线程共用JavaVM;

JNIEnv

  JNIEnv它是一个与线程相关的用来代表java运行环境的,用来进行java-native互调的一个结构体,内部包含了一个JNI本地接口指针【JNINativeInterface* functions】,这个指针又指向了函数指针数组【定义了JNI相关的函数指针】;
  同一个线程调用本地方法,JNIEnv是同一个,不同线程调用native方法,JNIEnv不相同【java可以在不同线程中调用】

jobject

  Native方法中传递过来的jobject其实就是一个java实例引用,实例就是一个具体的对象,这个native方法是一个具体的java对象调用的!

jclass

  Native方法中传递过来的jclass就是一个java类引用,这个native方法是一个静态类方法,jclass其实这个类引用!

JNI数据类型 基本类型

JNI基本类型,可以直接拿来使用,本质还是C/C++的基本数据类型,只不过使用typedef定义了而已!

引用类型

引用类型不能直接使用,必须通过JNIEnv中的JNI函数转换后,才能够使用!

类型描述

字符串

public native String getNaitiveName(String name);
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_ndkdemo_MainActivity_getNaitiveName(
        JNIEnv *env,
        jobject thiz,
        jstring name) {

    int strLen = 0;
    
    strLen = env->GetStringLength(name);

    
    
    
    const char* pStr = env->GetStringUTFChars(name,NULL);
    env->ReleaseStringUTFChars(name,pStr);

    
    
    const jchar* pjStr = env->GetStringChars(name,NULL);
    env->ReleaseStringChars(name,pjStr);

    
    jstring jNewStr = env->NewStringUTF("Haha");
    strLen = env->GetStringUTFLength(jNewStr);

    
    jstring jOutStr = env->NewStringUTF("gaga");
    char outStrBuffer[128] = {0};
    int outStrLen = 0;
    outStrLen = env->GetStringLength(jOutStr);
    env->GetStringUTFRegion(jOutStr,0,outStrLen,outStrBuffer);//GetStringRegion unicode
    jOutStr =  env->NewStringUTF(outStrBuffer);

    return jOutStr;
}
数组
public native String getArrayToStr(int[] ary);
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_ndkdemo_MainActivity_getArrayToStr(
        JNIEnv *env,
        jobject thiz,
        jintArray ary) {
    
    
    int iNumAry[128];
    int jAryLen = 0;
    jAryLen = env->GetArrayLength(ary);
    env->GetIntArrayRegion(ary,0,jAryLen,iNumAry);

    
    std::string strRet = "";
    for(int i=0;i
        strRet += std::to_string(iNumAry[i]);
    }

    
    jstring jStrRet = env->NewStringUTF(strRet.c_str());
    return jStrRet;
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_ndkdemo_MainActivity_getArrayToStr(
        JNIEnv *env,
        jobject thiz,
        jintArray ary) {
    
    jint* jAry = env->GetIntArrayElements(ary,NULL);
    if(!jAry){
        return 0;
    }

    
    std::string strRet = "";
    int jAryLen = env->GetArrayLength(ary);
    for(int i=0;i
        strRet += std::to_string(jAry[i]);
    }

    
    env->ReleaseIntArrayElements(ary,jAry,0);

    
    jstring jStrRet = env->NewStringUTF(strRet.c_str());
    return jStrRet;
}

Naitive构造一维数组:

public native int[] newArrayFromNative();
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_ndkdemo_MainActivity_newArrayFromNative(JNIEnv *env, jobject thiz) {
    int nums[10] = {5,2,1};
    jintArray jAry = env->NewIntArray(10);
    env->SetIntArrayRegion(jAry,0,10,nums);
    return jAry;
}
属性
  • 获取/修改实例属性
    public String name = "哈哈";
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myjnifieldfunc_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject jobj) {

    //获取jclass
    jclass jcls = env->GetObjectClass(jobj);

    //获取jFieldID
    jfieldID jfId = env->GetFieldID(jcls,"name", "Ljava/lang/String;");
    if(!jfId){
        return env->NewStringUTF("");
    }

    //Java:String -> JNI:jstring
    jstring jName;
    jName = env->NewStringUTF("嘎嘎");
    env->SetObjectField(jobj,jfId,jName);

    jstring jRetStr;
    jRetStr = static_cast(env->GetObjectField(jobj, jfId));

    return jRetStr;
}
  • 获取/修改全局属性
static public String gName = "全局奥利给";
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnifieldfunc_MainActivity_gstringFromJNI(
        JNIEnv *env,
        jclass clazz) {
    //获取FieldId
    jfieldID jfId = env->GetStaticFieldID(clazz,"gName", "Ljava/lang/String;");
    //修改FieldValue
    jstring jValue = env->NewStringUTF("我改了,你咋滴!");
    env->SetStaticObjectField(clazz,jfId,jValue);
}
方法
    public void PrintLog(){
        Log.d("MainActivity", "PrintLog: Native->Java");
    }

    public static void PrintStaticLog(){
        Log.d("MainActivity", "PrintStaticLog: Native->Java");
    }
    
	public native void CallJavaFuncFromJNI();
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnifieldfunc_MainActivity_CallJavaFuncFromJNI(
        JNIEnv *env,
        jobject jobj) {
    //jclass
    jclass jcls = env->GetObjectClass(jobj);
    jmethodID jmId = env->GetMethodID(jcls,"PrintLog", "()V");
    if(!jmId){
        return;
    }
    //call 成员方法
    env->CallVoidMethod(jobj,jmId);

    jmethodID jgmId = env->GetStaticMethodID(jcls,"PrintStaticLog","()V");
    if(!jgmId){
        return;
    }
    //call 全局方法
    env->CallStaticVoidMethod(jcls,jgmId);
}
局部引用-全局引用
  • 局部引用
    Native方法作用域中创建的引用对象,返回的引用被称之为局部引用,只能在本Native方法以及调用Native方法的范围内使用,执行完毕离开作用域会被自动释放,没有被释放前,是不能被垃圾回收的,不能保存局部引用至全局【内存异常或系统崩溃】!
    **局部引用手动释放:**DeleteLocalRef
  • 全局引用
    NewGlobalRef唯一创建全局引用API【局部引用的区别】
    DeleteGlobalRef 释放全局引用
    都是需要手动创建和释放!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1030727.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号