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 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android扩展知识 - 不同so文件间的调用 -> 正文阅读

[移动开发]Android扩展知识 - 不同so文件间的调用

博客借鉴
Android NDK、JNI之- -(二)c代码中调用so文件

修改Android Studio工程目录中的package

  • 切换到Project模式下,工程目录中的package是com.example.testndk4,想要修改成my.testndk4。
  • 在这里插入图片描述
    • 首选删除原来的package,右键com.example.testndk4,弹出菜单中选择Delete,会发现package只剩下com.example
    • 继续右键Delete,则完全删除package。
  • 新建package --> my.testndk4
    • 直接右键java目录,新建package为my.testndk4
  • 在新建package下,新建MainActivity
  • 在相关文件中修改package的配置,否则会出错。
    • 首先是AndroidManifest.xml文件

      • 在这里插入图片描述
    • 然后是app下的build.gradle

      • 在这里插入图片描述
    • 然后是MainActivity

      • 在这里插入图片描述
  • 经过以上操作,便可以编译运行,不会出错了。

开发一个libDemoA.so文件

配置ndk-bundle路径

  • local.properties文件中添加代码如下:
    • ndk.dir=D\:\\JAVA\\tools\\Android Studio\\Android_Sdk\\ndk-bundle

创建DemoA.java文件

  • java目录下新建package为cn.fhy
  • 在cn.fhy包中新建DemoA.java类,编写代码如下:
package cn.fhy;

public class DemoA {
    
    private native String getName();

    private native int getAge();

    private native boolean isMale();

    private native int getAdditionResult(int x,int y);

    private native void showSomething();
    
}

生成.h文件

  • 终端窗口切换到java目录下,然后编译cn.fhy.DemoA文件,如下所示:
  • 在这里插入图片描述
  • 编译之后便可以看到目录中生成cn_fhy_DemoA.h文件

新建jni文件夹

  • 右键app,new – Folder – JNIFolder

将cn_fhy_DemoA.h文件移到jni文件夹中

在jni文件夹中新建DemoA.c文件

  • 根据生成的cn_fhy_DemoA.h文件我们写下DemoA.c文件,代码如下:
//
// Created by FHY on 2022-04-29.
//

#include <string.h>
#include <jni.h>
#include <android/log.h>


jstring Java_cn_fhy_DemoA_getName(JNIEnv * env, jobject obj){
    char * str = "我来自DemoA.so,我的昵称是fhy!";
    return (*env) -> NewStringUTF(env,str);
}

jint Java_cn_fhy_DemoA_getAge(JNIEnv * env, jobject obj){
    return 22;
}

jboolean Java_cn_fhy_DemoA_isMale(JNIEnv * env, jobject obj){
    return JNI_TRUE;
}

jint Java_cn_fhy_DemoA_getAdditionResult(JNIEnv * env, jobject obj, jint x, jint y){
    return x + y;
}

void Java_cn_fhy_DemoA_showSomething(JNIEnv * env, jobject obj){
    __android_log_print(ANDROID_LOG_ERROR,"DemoA,so","这是来自DemoA.so的jniShowSomethign()方法!");
}

在jni文件夹中新建Android.mk文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

#加入这句可以使得so文件打印日志
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog

LOCAL_MODULE:= DemoA

LOCAL_SRC_FILES := DemoA.c

include $(BUILD_SHARED_LIBRARY)

编译生成so文件

  • 终端命令窗口,在java目录下,输入ndk-build
  • 在这里插入图片描述
  • 可以看到目录中生成的 libsobj 文件夹。
  • 此时我们在app目录下新建一个 jniLibs 文件夹,如下:
  • 然后将libs中的内容全部复制过去,注意同时分arm64-v8a、armeabi-v7a、x86、x86_64四个子文件夹。
  • 在这里插入图片描述

配置调用so文件的路径

  • 在app下的build.gradle文件中添加代码如下:
  • 在这里插入图片描述

调用so文件

  • 首先在DemoA.java中添加代码如下:

  • 在这里插入图片描述

  • 再在MainActivity中添加代码:

  • 在这里插入图片描述

  • 编译运行程序,在日志窗口中看到如下信息,便表示编译成功。

  • 在这里插入图片描述

开发一个libDemoB.so文件

创建DemoB.java文件

  • 新建package,com.fhy
  • 在com.fhy包中新建DemoB类
package com.fhy;

public class DemoB {
    private native String getName();

    private native int getAge();

    private native boolean isMale();

    private native int getAdditionResult(int x,int y);

    private native void showSomething();
}

直接编写Demo.c文件

  • 为什么不先编译生成.h文件,再写.c文件呢?
    • 因为这个libDemoB.so文件就是为了调用libDemoA.so文件里面的方法的,所以,我们直接仿照DemoA.c文件来写DemoB.c文件。
  • jni 文件夹中新建Demo.c文件
//
// Created by FHY on 2022-04-29.
//

#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <android/log.h>

JNIEXPORT jstring JNICALL Java_com_fhy_DemoB_getName(JNIEnv * env, jobject obj){
    jstring result = "小明";
    void * handle = dlopen("libDemoA.so", RTLD_LAZY );
    if(handle){
        jstring (* getName)(JNIEnv*, jobject);
        getName = (jstring ( * ) (JNIEnv*, jobject)) dlsym(handle, "Java_cn_fhy_DemoA_getName");
        if(getName){
            result = getName(env, obj);
        }
        dlclose(handle);
        handle = NULL;
    }
    return result;
}

JNIEXPORT jint JNICALL Java_com_fhy_DemoB_getAge(JNIEnv * env, jobject obj){
    jint result = 16;
    void * handle = dlopen("libDemoA.so", RTLD_LAZY );
    if(handle){
        jint (* getAge)(JNIEnv*, jobject);
        getAge = (jint ( * ) (JNIEnv*, jobject)) dlsym(handle, "Java_cn_fhy_DemoA_getAge");
        if(getAge){
            result = getAge(env, obj);
        }
        dlclose(handle);
        handle = NULL;
    }
    return result;
}

JNIEXPORT jboolean JNICALL Java_com_fhy_DemoB_isMale(JNIEnv * env, jobject obj){
    jboolean result = 16;
    void * handle = dlopen("libDemoA.so", RTLD_LAZY );
    if(handle){
        jboolean (* isMale)(JNIEnv*, jobject);
        isMale = (jboolean ( * ) (JNIEnv*, jobject)) dlsym(handle, "Java_cn_fhy_DemoA_isMale");
        if(isMale){
            result = isMale(env, obj);
        }
        dlclose(handle);
        handle = NULL;
    }
    return result;
}

JNIEXPORT jint JNICALL Java_com_fhy_DemoB_getAdditionResult(JNIEnv * env, jobject obj, jint x, jint y){
    jint result = 0;
    void * handle = dlopen("libDemoA.so", RTLD_LAZY );
    if(handle){
        jint (* getResult)(JNIEnv*,jobject, jint, jint);
        getResult = (jint ( * ) (JNIEnv*, jobject, jint, jint)) dlsym(handle, "Java_cn_fhy_DemoA_getAdditionResult");
        if(getResult){
            result = getResult(env, obj, x, y);
        }
        dlclose(handle);
        handle = NULL;
    }
    return result;
}

JNIEXPORT void JNICALL Java_com_fhy_DemoB_showSomething(JNIEnv * env, jobject obj){
    void * handle = dlopen("libDemoA.so", RTLD_LAZY );
    if(handle){
        void (* showSomething)(JNIEnv*,jobject);
        showSomething = (void ( * ) (JNIEnv*, jobject)) dlsym(handle, "Java_cn_fhy_DemoA_showSomething");
        if(showSomething){
            showSomething(env, obj);
        }
        dlclose(handle);
        handle = NULL;
    }
}
  • 具体代码解释可以我上面贴的借鉴博文-

修改Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

#加入这句可以使得so文件打印日志
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog

LOCAL_MODULE:= DemoB

LOCAL_SRC_FILES := DemoB.c

include $(BUILD_SHARED_LIBRARY)

编译生成libDemoB.so文件

  • 终端命令窗口,java目录下,输入ndk-build命令行
  • 此时可以看到libs文件夹中的内容更新了,由libDemoA.so更新成libDemoB.so文件。

解释下为什么这里新建jniLibs

  • 因为libs文件夹只能存在一种.so文件,而后面调用的时候必然同时调用libDemoA.so和libDemoB.so,所以需要将两种so文件放在同一个文件夹中,因此创建jniLibs,当做是自己的so库。
  • 当然肯定还有其他解决方法,比如Android.mk代码修改,只不过我不会,就用这种比较笨的方法。

将libDemoB.so文件复制到jniLibs文件夹中

  • 此时jniLibs文件目录如下:
  • 在这里插入图片描述

调用libDemoB.so文件

  • DemoB.java
  • 在这里插入图片描述
  • MainActivity
  • 在这里插入图片描述
  • 最后运行程序,Log窗口输出信息如下:
    在这里插入图片描述
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-01 15:53:47  更:2022-05-01 15:53:53 
 
开发: 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/25 0:08:53-

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