当前位置:   article > 正文

Android studio 链接linux环境下ndk编译的so库_将linux的platform的so依赖放入android

将linux的platform的so依赖放入android

内容如其名,纯小白从零开始搞这个。原因是学长说要用as链接linux下ndk编译的so库,而不能直接用as生成,那么好的工具,说不用就不用了。不过既然有要求,那咱也不能含糊,脱下裤子,不不不,撸起袖子就是干。

神奇的又有了更新,下面是调用非JNI标准的函数的步骤,在最后面会加上调用标准JNI函数的步骤

调用非JIN标准函数

1 搭建的环境

windows10 1803版

VirtualBox 5.2.14版本下的debian-9.5.0-armd64虚拟机

Android studio 3.2


2 linux方面

首先配置好NDK环境

1下载ndk https://developer.android.google.cn/ndk/downloads/

2 解压 unzip <filename.zip>

3 配置环境变量

#vim /etc/profile 在文件末尾添加如下

export ANDROID_NDK=“ndk路径”
export PATH="$ANDROID_NDK:$PATH" 
  • 1
  • 2

4.更新系统变量

#source /etc/profile

5.检查ndk环境配置正确与否

#ndk-build

//出现如下界面即配置成功

AndroidNDK: Could not find application project directory !

Android NDK: Please define the NDK_PROJECT_PATH variable topoint to it.

/android-ndk-r16b/build/core/build-local.mk:151: *** Android NDK: Aborting . Stop.


3 linux下用ndk编译成so

新建一个文件夹jni,然后在jni文件夹下

首先需要cpp和h文件,我的只是简单做个例子,如下

testC.h

#ifndef TESTC_H
#define TESTC_H
int testC();
#endif
  • 1
  • 2
  • 3
  • 4

testC.cpp

#include "testC.h"
int testC()
{
	return 6;
}
  • 1
  • 2
  • 3
  • 4
  • 5

Android.mk

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

APP_ABI := all             # 编译类型为适配所有架构的cpu
APP_PLATFORM := android-28 # 对应版本是28

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

编译命令

ndk-build APP_ABI=all
  • 1

会在jni同级目录下生成两个文件夹,libs和obj,libs文件夹下即为刚编译的so库


另: 如果你的cpp或者h文件引入了标准库文件的函数,如

#include <string>
  • 1

这样执行编译命令的时候会报一个错

ndk-build error string No such file or directory
  • 1

解决方法是在jni目录下新建一个文件Application.mk

里面添加

APP_STL := gnustl_static
  • 1

即可找到标准库


4 as方面

新建一个项目,记得勾选include C++ support

在这里插入图片描述

然后一路下一步就可以了,然后把linux下编译生成的so文件 放到app下的libs文件夹下

在这里插入图片描述

本图已经放进来了

然后编写Cmakelist.txt,里面已经有新建项目是自动生成的东西,注意区分

# 动态方式加载 libtestC.so
add_library(testC SHARED IMPORTED)
# 设置链接so的路径,${ANDROID_ABI}为so文件的cpu架构类型
set_target_properties(testC  PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libtestC.so)

# 这个原先中有,在其中添加上testC即可
target_link_libraries(testC)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

因为没有主函数,所以直接在系统自动生成的样例函数中测试自己的so库,也就是native-lib.cpp文件,记得把h问价传进as

在这里插入图片描述

注意,红框的地方是修改了的

然后编译运行就可以了。

这里有一个问题,如果没报错但是app闪退,那么就在buiild.gradle android里添加

    sourceSets{
        main{
            jniLibs.srcDirs = ['libs']
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5

5 完整项目地址

下面是完整的我的demo地址

https://github.com/xixihahag/first_ndk

6 其它错误

在as编译出现下面的问题

Build command failed.
Error while executing process C:\sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build D:\myasworkspace\test2_include_c++_support\app\.externalNativeBuild\cmake\debug\armeabi-v7a --target native-lib}
ninja: error: '../../../../app/libs/armeabi-v7a/libtestC.so', needed by '../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so', missing and no known rule to make it
  • 1
  • 2
  • 3

原因是在CMakeLists.txt中
原命令
set_target_properties(testC  PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/app/libs/${ANDROID_ABI}/libtestC.so)
  • 1

修改后的命令

set_target_properties(testC  PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libtestC.so)
  • 1

错误原因

as中好像找不到

${PROJECT_SOURCE_DIR}
  • 1

这个地址,改为

${CMAKE_SOURCE_DIR}
  • 1

后就好了


调用JNI标准函数过程,这个可简单多了,虽然上面的也不难


JNI标准就是cpp文件中的函数名的命名是

Java_包名_类名_函数名
  • 1

自己参照官网例子写的一个简单的如下
testJni.cpp

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_immortals_myapplication_MainActivity_stringFromMyJNI(
    JNIEnv *env,
    jobject /* this */)
{
    std::string hello = "Hello from myJNI";
    return env->NewStringUTF(hello.c_str());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

修改了Android.mk文件,顺便加上了很多注释

LOCAL_PATH:=$(call my-dir) # my-dir就是该Android.mk所在目录,将这个目录复制给CAL_PATH变量
include $(CLEAR_VARS) # 清除此行之前除了LOCAL_PATH外所有的变量,因为定义的多个模块中会有相同名称的变量,目的是避免变量赋值冲突  
LOCAL_MODULE :=testJni # 指定一个当前模块名
LOCAL_SRC_FILES:=testJni.cpp #  要编译的源文件
include $(BUILD_SHARED_LIBRARY) # 编译目标 表示编译成动态库 即so库
#include $(PREBUILT_SHARED_LIBRARY)  # 编译目标,PREBUILT_表示已经编译好的,在使用NDK编译时不会再次编译,而是直接拷贝到libs目录  
                                     # 预编译.a静态库使用 PREBUILT_STATIC_LIBRARY  

APP_ABI := all
APP_PLATFORM := android-28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

然后在linux下用ndk-build生成so文件后,复制到上文所说的libs里面,因为类名写的是MainActivity,所以就直接在主函数里添加引用和声明即可,主函数如下,红框是修改的地方。

在这里插入图片描述

直接编译运行,跑,完事。

一个小问题

No implementation found for java.lang.String
  • 1

错误原因

大概率是cpp文件中的函数命名和包名不一致,改成一致就可以了


Ps.下面看不懂可以直接跳过

关于学长说导出jar包和so文件就可以给别人用的问题

因为JNI是有命名规范的,上面说过是

Java_包名_类名_函数名
  • 1

所以只要自己写一个java类,然后再类里面声明自己写的函数就可以了


防止有人看不懂,小例子


testJni.cpp

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
// 注意这个函数名的类名改成了JniUtils
Java_com_example_immortals_myapplication_JniUtils_stringFromMyJNI(
    JNIEnv *env,
    jobject /* this */)
{
    std::string hello = "Hello from myJNI";
    return env->NewStringUTF(hello.c_str());
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在和MainActivity.java同级的目录下新建一个class叫JniUtils.java
内容

package com.example.immortals.myapplication;

public class JniUtils {
    static {
        System.loadLibrary("testJni");
    }
	// 注意 函数报红是没问题的
    public native String stringFromMyJNI();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

主函数的修改
在这里插入图片描述
照例,红框部分是修改了的

然后,编译,跑。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/1017456
推荐阅读
相关标签
  

闽ICP备14008679号