• JNI,NDK


    jni的调用过程
    1)安装和下载Cygwin,下载Android NDK
    2)在ndk项目中JNI接口的设计
    3)使用C/C++实现本地方法
    4)JNI生成动态链接库.so文件
    5)将动态链接库复制到java工程,在java工程中调用,运行java工程即可

    NDK

    1.NDK是一系列工具的集合,帮助开发者迅速的开发C/C++的动态库,并能自动将so和java应用打成apk包

    2.NDK集成了交叉编译器,并提供了相应的mk文件和隔离cpu、平台等的差异,开发人员只需简单的修改mk文件就可以创建出so

    交叉编译
      在一个平台下,编译出另一个平台能够执行的二进制的代码
      平台:windows,mac os,linux
      处理器:x86,arm,mips
    交叉编译的原理
      源代码->编译->链接->可执行程序
      模拟其他平台的特性
    交叉编译的工具链
      多个工具的集合,一个工具使用完后接着调用下一个工具

    常见工具
      NDK:native developement kit:开发jni必备,就是模拟其他平台特性来编译代码的工具
      CDT:C/C++ developement tools:高亮显示c语言关键字
      cygwin:一个模拟器,可以再windows下运行linux指令

    NDK目录结构
      docs:帮助文档
      build/tools:linux的批处理文件
      platforms:编译c代码需要使用的头文件和类库
      prebuilt:预编译使用的二进制可执行文件
      sample:jni的使用例子
      source:ndk的源码
      toolchains:工具链
      ndk-build.cmd:编译打包c代码的一个指令

    * 使用C语言实现本地方法

    1. 在项目根目录下创建jni文件夹
    2. 在jni文件中创建一个c文件
    3. 在java代码中,创建一个本地方法helloFromC

    //native关键字
    public native String helloFromC();

    4. 在jni中定义函数实现这个方法,函数名必须为

    //返回值 报名_类名_方法名(参数参照例子)
    jstring Java_com_itheima_helloworld1_MainActivity_helloFromC(JNIEnv* env, jobject obj)

    5. 返回一个字符串,用c定义一个字符串

    char* cstr = "hello from c";

    6. 把c的字符串转换成java的字符串

    jstring jstr = (*env)->NewStringUTF(env, cstr);
    return jstr;

    7. 在jni中创建Android.mk文件
    8. 在c文件中添加<jni.h>头文件
    9. 在jni文件夹下执行ndk-build.cmd指令
    10. java代码中加载so类库,调用本地方法(so是C语言的类库)

    static{
        //加载打包完毕的so类库
        System.loadLibrary("hello");
    }

    代码

    MainActivity

    public class MainActivity extends Activity {
    
        static{
            //加载打包完毕的so类库
            System.loadLibrary("hello");
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void click(View v){
            Toast.makeText(this, helloFromC(), 0).show();
        }
        
        //定义一个本地方法,方法体由c语言实现
        public native String helloFromC();
    }

    Hello.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <jni.h>
    
    jstring Java_com_itheima_helloworld1_MainActivity_helloFromC(JNIEnv* env, jobject obj){
        //c语言的字符串
        char* cstr = "hello from c";
        //把C语言的字符串转换成java的字符串
        // jstring     (*NewStringUTF)(JNIEnv*, const char*);
    //    jstring jstr = (*(*env)).NewStringUTF(env, cstr);
        jstring jstr = (*env)->NewStringUTF(env, cstr);
        return jstr;
    }

    Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    #编译生成的文件的类库叫什么名字
    LOCAL_MODULE    := hello
    #要编译的c文件
    LOCAL_SRC_FILES := Hello.c
    
    include $(BUILD_SHARED_LIBRARY)

    * 实现两个数相加

    public class MainActivity extends Activity {
        static{
            System.loadLibrary("hello");
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
    
        public void click(View v){
            Toast.makeText(this, "3+5的和为" + add(3, 5), 0).show();
        }
        
        public native int add(int i, int j);
        
    }

    Android.mk

     LOCAL_PATH := $(call my-dir)
    
        include $(CLEAR_VARS)
    
        LOCAL_MODULE    := hello
        LOCAL_SRC_FILES := Hello.c
    
        include $(BUILD_SHARED_LIBRARY)

    Hello.c

    #include <jni.h>
    
    jint Java_com_itheima_helloworld2_MainActivity_add(JNIEnv* env, jobject obj, jint i, jint j){
    
        return i + j;
    }

    Application.mk

    APP_ABI := all //支持arm、mips、x86等所有架构

    * javah
      1.7:在src目录下执行javah 包名.类名
      1.6:在bin/classes目录下执行

    然后工程刷新,复制里面已经自动生成的方法名,就可以粘贴到c文件中使用

    * 配置NDK路径

    perference->android->ndk

    右键->android tools->add native support可以自动生成jni和mk文件

    关联源码:properties->C/C++ general->paths and symbols(源码路径:ndkplatformsandroid-18arch-armusrinclude)

    * 传递整形数组

    public class MainActivity extends Activity {
    
        static{
            System.loadLibrary("hello");
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        int[] arr = {1,2,3,4,5};
    
        public void click(View v){
            arrayEncode(arr);
            for (int i : arr) {
                System.out.println(i);
            }
        }
        
        public native void arrayEncode(int[] arr);
    }

    Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE    := hello
    LOCAL_SRC_FILES := hello.c
    
    include $(BUILD_SHARED_LIBRARY)

    hello.c

    #include <jni.h>
    
    JNIEXPORT void JNICALL Java_com_itheima_array_MainActivity_arrayEncode
      (JNIEnv * env, jobject obj, jintArray jintarr){
        //拿到整型数组的长度以及第0个元素的地址
         //jsize       (*GetArrayLength)(JNIEnv*, jarray);
        int length = (*env)->GetArrayLength(env, jintarr);
         //jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
        int* arrp = (*env)->GetIntArrayElements(env, jintarr, 0);
    
        int i;
        for(i = 0;i < length; i++){
            *(arrp + i) += 10;
        }
    }

    * 调用美图秀秀的本地方法(只需复制粘贴美图秀秀的so文件,并不需要创建jni文件)

    public class MainActivity extends Activity {
    
        private Bitmap bm;
        private ImageView iv;
    
        static{
            System.loadLibrary("mtimage-jni");
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            bm = BitmapFactory.decodeFile("sdcard/aneiyi.jpg");
            iv = (ImageView) findViewById(R.id.iv);
            iv.setImageBitmap(bm);
        }
    
        public void click(View v){
            int width = bm.getWidth();
            int height = bm.getHeight();
            
            //用于保存所有像素信息
            int[] pixels = new int[width * height];
            //获取图片的像素颜色信息,保存至pixels
            bm.getPixels(pixels, 0, width, 0, 0, width, height);
            
            JNI jni = new JNI();
            //arg0:保存了所有像素颜色信息的数组
            //arg1:图片的宽
            //arg2:图片的高
            //此方法是通过改变pixels的像素颜色值来实现美化效果
            jni.StyleLomoC(pixels, width, height);
            
            Bitmap bmNew = Bitmap.createBitmap(pixels, width, height, bm.getConfig());
            iv.setImageBitmap(bmNew);
        }
    }

    * 在C代码中打印log日志

    第一步:Android.mk文件增加LOCAL_LDLIBS += -llog

    第二步:C代码中增加

    #include <android/log.h>
    #define LOG_TAG "System.out"
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__)
    
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__)
    
    LOGI("info
    ");
    LOGD("debug
    ");

     * 在C中用反射调用JAVA中方法

    public class MainActivity extends Activity {
        static{
            System.loadLibrary("hello");
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void click(View v){
            helloC();
        }
        
        public native void helloC();
        
        public void show(String message){
            Builder builder = new Builder(this);
            builder.setTitle("БъЬт");
            builder.setMessage(message);
            builder.show();
        }
    }

    Android.mk

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_LDLIBS += -llog
    
    LOCAL_MODULE    := hello
    LOCAL_SRC_FILES := hello.c
    
    include $(BUILD_SHARED_LIBRARY)

    hello.c

    #include <jni.h>
    #include <android/log.h>
    #define LOG_TAG "System.out"
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
    
    
    JNIEXPORT void JNICALL Java_com_itheima_ccalljava_MainActivity_helloC
      (JNIEnv * env, jobject obj){
        
        LOGD("hello!");
        LOGI("hello!");
        //jclass      (*FindClass)(JNIEnv*, const char*);
        jclass clazz = (*env)->FindClass(env, "com/itheima/ccalljava/MainActivity");
        //jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
        jmethodID methodID = (*env)->GetMethodID(env, clazz, "show", "(Ljava/lang/String;)V");
        //void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
        (*env)->CallVoidMethod(env, obj, methodID, (*env)->NewStringUTF(env, "是时候再黑一波小志了"));
    }

     

  • 相关阅读:
    Android 中adb 命令(实用)
    Mac安装Scala
    使用阿里云镜像maven管理配置开发环境
    Nginx学习笔记3--Nginx和PHP(fastCGI)的配置和优化
    《实战Nginx》读书笔记--Nginx配置文件
    《实战Nginx》读书笔记
    PHP解码unicode编码中文字符代码
    yii学习笔记--使用gii快速创建控制器和模型
    yii学习笔记--配置文件的配置
    yii学习笔记--快速创建一个项目
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/5574039.html
Copyright © 2020-2023  润新知