吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5729|回复: 55
收起左侧

[Android 原创] 折腾折腾用android studio去编写so

  [复制链接]
欧雨鹏 发表于 2020-10-21 17:11
本帖最后由 欧雨鹏 于 2020-10-23 22:06 编辑

(各位大哥大姐,咳 咳 ,看在我写的这么辛苦的份上。能不能看完整篇文章后,辛苦一下动动手指头,点一下评分。。谢谢了!)

如果想看如何用JNI_onLoad注册方法,请移架下面的贴子
折腾折腾用android studio去编写so--动态注册 https://www.52pojie.cn/thread-1289375-1-1.html

序言
个人只学过c/c++和c#语法,用的相关工具比较多。此前还没碰过android studio工具,JAVA代码也算大概看得懂吧。
为了写一个so。对着android studio这工具死命折腾。project创建了一个又一次。同样的事情不知道做了多少次。总算有一两次成功了。
现在只能做一做笔记,以免忘记。

由于刚开始折腾时,有些心躁。看着前辈们曾经发的贴子,跟着一遍一遍做。问题总是出现。接着就是修改host,添加sdk版本,更新Tools,有什么搞什么。。结果不知道哪脑子卡了。点了update..好了,直接update了。。图标变白了,界面变白了。一看版本,直接把版本给更新了。现在是4.1版本

a1

a1

v2

v2

最后,还是没看到前辈们贴子里提到的LLDB这个玩意。

v3

v3

但这不影响。起码最后操作成功。

android studio版本 4 .1SDK TOOLS;默认添加了cmake,NDK没有LLDB这个东西。主要用到了NDK和CMAKE
创建工程用到的android 5.1版本

先来一遍操作过程再说。

1.把工程创建起来

v4

v4


2.在java层的com.xxxx包里面添加一个类,这个类要用做什么?加载so,和声明native。简单的写法,写太复杂怕搞不定。
选中com.hello.myapplication4,右键--new---java class

v6

v6

弹出这么一个对话框,没有确定按钮,好吧。这肯定是一个回车就搞定的玩意,上面输入名称就可以了:jniText

v5

v5

然后又弹出这么一个对话框。虽然不是很想理它。但是还是搜了一下。

v7

v7

(1).IMPORT_BLOCK - 以换行符分隔的列表,其中包含支持任何父类或接口所需的 Java import 语句,或为空字符串 ("")。例如,如果您仅实现 Runnable 接口而不扩展任何内容,则此变量将为 “import java.lang.Runnable;\n”。如果您实现 Runnable 接口并扩展 Activity 类,则此变量将为 “import android.app.Activity;\nimportjava.lang.Runnable;\n”。

(2).VISIBILITY - 相应类是否具有公开访问权限。其值可以为 PUBLIC 或 PACKAGE_PRIVATE。

(3).SUPERCLASS - 单个类名称,或为空。如果存在,则新类名称后面将有一个 extends ${SUPERCLASS} 子句。

(4).INTERFACES - 以英文逗号分隔的接口列表,或为空。如果存在,则父类后面将有一个 implements ${INTERFACES} 子句;如果没有父类,则类名称后面将有一个该子句。对于接口和注释类型,接口具有 extends 关键字。

(5).ABSTRACT - 相应类是否应为抽象类。其值可以为 TRUE 或 FALSE。

(6).FINAL - 相应类是否应为最终类。其值可以为 TRUE 或 FALSE。
注:上面的解释内容来自:https://blog.csdn.net/weixin_37077736/article/details/107460139

啥都不填,直接回车。

这样就生成了一个jniText类

v8

v8

添加代码,代码如下:
[C] 纯文本查看 复制代码
package com.hello.myapplication4;

class jniText {
    static{
        System.loadLibrary("loadNewSo");//loadNewSo这个名称自己设置
    }
    public static native String getStringMyName();//声明native方法,实现是在c/c++中实现
}



3.jniText这个类创建好了,代码也写好了。下面就要先把它生成.class文件。不要问为什么要生成.class文件。问就是回答。
.class结尾的文件是java的字节码文件,里面存放的是我们对java源码编译后产生的二进制代码.

操作方法:Build---Rebuild Project
ReBuild完成后,在路径build\intermediates\javac\debug\class\com\hello\myapplication4里查看之前创建的类是不是生成了.class文件。

v9

v9



4.上面的jni文件对native层的声明已经处理完毕。接下来是不是要实现它了。所以要创建c/c++的实现文件。这里选择用c文件。
(1)先生成一个与native相关的h文件。
就是刚刚创建的jniText类的java层。
在main层创建一个Jni文件夹:New---Folder---JNI Folder

v10

v10


alt+f12调出terminal,如果有就不用了。cd到java层。因为要生成h文件的是com.hello.myapplication4.jniText这个类。所以要进入java层

v12

v12

执行javah命令,生成h文件到jni文件夹里。(注:这里操作的时候,提示:编码GBK的不可映射字符。是因为注释是中文的。去掉了就正常了。)
执行命令如下:
[C] 纯文本查看 复制代码
javah -d E:\DownLoad\MyApplication4\app\src\main\jni com.hello.myapplication4.jniText

或者
[C] 纯文本查看 复制代码
javah -d ../jni com.hello.myapplication4.jniText

注:javah -d 生成路径 包名.类名
生成完成后可以在jni文件夹里看到生成的h文件。

v13

v13

双击打开查看生成了相关代码

v14

v14

(2).后面就可以继续在jni文件夹里创建c文件了。当然c++文件也行。
操作:New--C/C++ Source File,文件名合法随意取(后面设置时用到),格式有.c和.cpp两种格式选择

v15

v15


添加实现代码:
[C] 纯文本查看 复制代码
#include "com_hello_myapplication4_jniText.h"
JNIEXPORT jstring JNICALL Java_com_hello_myapplication4_jniText_getStringMyName
  (JNIEnv *env, jclass obj)
  {
    return (*env)->NewStringUTF(env,"pady");
  }


上面的c文件就完成了。下面就可以着手开始配置然后生成so文件。
对,Activity层还得调用它。先给TextView设置个id先

v16

v16

v17

v17


5.配置文件属性并生成so

gradle.properties添加module
[C] 纯文本查看 复制代码
ndk{
    moduleName "loadNewSo"
}

gradle.properties这个配置文件有什么作用?刚好找到一个解释:
在项目编译过程中,gradle.properties配置的值会被编译解析,其作为配置文件使用是很有必要的
添加好了,点一下sync now检查一下。

v18

v18


然后是配置build.gradle添加节点。注意,android studio有两个build.gradle。需要操作的是app层里面的build.gradle,不是外面那个build.gradle。
不是外面的。不是外面的,不是外面的。
在defaultConfig节点添加以下内容:
[C] 纯文本查看 复制代码
externalNativeBuild{
        cmake{
            
            abiFilters 'arm64-v8a','armeabi-v7a','x86','x86_64'//生成多个版本的so文件
        }
    }


v19

v19

在android节点添加以下内容(这个是在android节点里面,在defaultConfig节点外面):
[C] 纯文本查看 复制代码
externalNativeBuild{
        cmake{
            path "CMakeLists.txt"//设置所要编写的C源码位置,以及编译后so文件的名字
        }
    }


v20

v20

完整内容如下:
[C] 纯文本查看 复制代码
android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"

    defaultConfig {
        applicationId "com.hello.myapplication4"
        minSdkVersion 22
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild{
            cmake{

                abiFilters 'arm64-v8a','armeabi-v7a','x86','x86_64'//生成多个版本的so文件
            }
        }

    }

    externalNativeBuild{
        cmake{
            path "CMakeLists.txt"//设置所要编写的C源码位置,以及编译后so文件的名字
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}


到上完的配置完成后,还差一个东西就可以开始生成so文件了。就是CMakeLists.txt.现在需要创建一个CMakeLists.txt。它用来做什么。做一些生成配置。
在app层里创建CMakeLists.txt.
操作如下:选中app,New---File,输入CmakeLists.txt,回车。这样就生成了一个txt文档
点击CMakeLists.txt,填写以下内容
[C] 纯文本查看 复制代码
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.
#CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        # 设置so文件名称.
        loadNewSo

        # Sets the library as a shared library.
        SHARED
        # 设置这个so文件为共享.

        # Provides a relative path to your source file(s).
        # 设置这个so文件为共享.
        src/main/jni/getName.c)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        # 制定目标库.
        loadNewSo

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib} )



上面就是所有内容了。需要修改的只有几部地方
第一处是add_library这里。括号里,第一个是loadLibrary的模块名称,即生成的名称会是这个。第二个是设置共享否,第三个是c源文件路径,之前创建的是getName.c,所以填写src/main/jni/getName.c
最后一处target_link_libraries,第一个也是loadLibrary的模块名称loadNewSo。这里要与jniText里面LoadLibrary的名称一致。

最后一步:Build--ReBuild Project

生成成功了。在路径build\intermediates\cmakes\debug\obj处,查看有没有生成各版本的so文件。如下图:

v21

v21


生成的debug.apk在build-outputs-apk--debug
右键show in explorer。打开文件夹,安装apk。
运行效果如下:

v22

v22


总结:其实整个过程并不复杂,就是java层创建jni类,生成class文件。再把java层的jni类生成c/c++的.h文件,再创建一个.c或.cpp源文件实现它。最后就是配置生成so.
===============================================================================================================
出现的问题:
在生成.class文件的操作过程中,除了rebuild外,还有一个javac手动命令。但是这个操作生成的class文件存放的路径可能导致出现下一步操作错误。

在java层里添加一个新类,不用rebuild生成class。手动javac生成。
在terminal里cd到E:\DownLoad\MyApplication5\app\src\main\java\com\hello\myapplication5
然后执行命令:javac myJNIutils.java
生成了myJNIutils.class

f1

f1

它生成后,是和同名的java文件放在一起。
接着要生成h文件。
cd到java层。
执行下面的命令:
[C] 纯文本查看 复制代码
E:\DownLoad\MyApplication5\app\src\main\java>javah -jni com.hello.myapplication5.myJNIutils

包名是:com.hello.myapplication5
类名是:myJNIutils
结果出现找不到类的提示了。反复确认,包名.类名。没错啊。但就是不成功。

f2

f2

为了证明是不是因为同名造成的冲突,把生成的.class文件去掉。改用rebuild生成class。

f3

f3

再执行命令:
[C] 纯文本查看 复制代码
E:\DownLoad\MyApplication5\app\src\main\java>javah -jni com.hello.myapplication5.myJNIutils

结果成功生成h文件。

f4

f4


原因是什么搞不清楚了,应该是这个4.1版本的android studio,出现同名不同格式的文件,执行javah时,造成冲突?

==================================================================================================================

上面是一系列的手动操作。有助于对过程的理解。下面是android studio另一个简洁操作。只需要改改名称就可以完成了。
1.新建工程的时候,选择Native C++

n1

n1


点Next,再选择C++标准。这里选择C++11

n2

n2


点finish后,就可以看到很多已经创建好了,包括CMakeLists.txt,cpp文件都自动创建好了。

n3

n3


只需要修改几个地方的名称就可以直接点ReBuild了。
Activity里,可以修改用于生成,加载的名称

n4

n4


然后就是修改CMakeLists.txt里面的内容。cpp的名称可以右键--Refactor---Rename,然后输入要修改的名称,确定。
在CMakeLists.txt里面,需要修改的就是上面改过的名称,还有cpp名称。

n5

n5

n6

n6


简单的总共就修改3个地方,然后直接Build---Rebuild project。

n7

n7


非常简单的操作。如果需要修改native,可以直接在activity里修改或者添加,在cpp里直接实现。方法只需要修改这两处就可以了。
总结:只需修改三个地方,activity--修改生成模块名称,修改cpp名称,修改CMakeLists.txt,把前面修改过的,在这里面都要修改成相同的名称。
参考文档:
https://www.52pojie.cn/thread-706568-1-1.html
https://blog.csdn.net/zhangmiaoping23/article/details/74390713
https://www.jianshu.com/p/997ae19a5fae
https://www.cnblogs.com/dubo-/p/7724059.html

最后不得不想说的是,写代码五分钟,写贴子五小时。实在太累人了。

免费评分

参与人数 11威望 +1 吾爱币 +29 热心值 +11 收起 理由
不会逆向 + 1 + 1 谢谢@Thanks!
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hack_wangyu + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
mygzv001 + 1 + 1 谢谢@Thanks!
608岁的老头 + 1 + 1 关于NDK的开发肯定少不了这个,如果还想深入多看点JNI的知识https://develo.
笙若 + 1 + 1 用心讨论,共获提升!
cka890712 + 1 热心回复!
Uindex + 1 + 1 我很赞同!
momo2021 + 1 + 1 谢谢@Thanks!
贰拾 + 1 + 1 用心讨论,共获提升!
alexskyboy + 1 + 1 为什么没人评分???

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 欧雨鹏 发表于 2020-10-21 18:00
carltian 发表于 2020-10-21 17:38
c++感觉比java复杂多了,还是java顺手

是不是看过多这篇文章觉得调用C/C++太复杂?其实那是早期的写法。IDE更新很快的。像VS也是更新很快。现在用VS,QT,这些开发都不那么痛苦。很多都会封装好。只需要简单的使用就可以了。就像android studio现在这个新建的native C++,也是帮我们处理好了,不需要像以前那样配置这个配置那个繁锁过程。IDE更新到现在,操作越来越简洁和方便了。只要熟悉它就不会有很大问题。
 楼主| 欧雨鹏 发表于 2020-10-21 23:18
战忽局滑稽 发表于 2020-10-21 20:21
楼主,你那android studio 什么版本的,我装的这个一直报这个,网上查了很久都解决不了

你这是东西还没下完全吧。中间那句话已经写得很明白了,项目没有成功同步。一般刚刚安装完android studio时,刚创建项目,会自动download一些东西的。
你可以试着设置一下SDK版本,TOOLS。
关闭android studio,再重新打开项目。网络保持顺畅 ,会有进条度,左下角会显示需要需要download的东西。
或者直接update版本。
jeanbood 发表于 2020-10-21 17:17
Luckyu920 发表于 2020-10-21 17:29
技术贴,受教了
wscb 发表于 2020-10-21 17:36
技术贴,受教
pisczx 发表于 2020-10-21 17:37
大神们的世界。
Jabez 发表于 2020-10-21 17:38

正好用上  感谢楼主
carltian 发表于 2020-10-21 17:38
c++感觉比java复杂多了,还是java顺手
tititui 发表于 2020-10-21 17:38
好的 学习一下
start01983 发表于 2020-10-21 17:38
谢谢楼主!!
Jabez 发表于 2020-10-21 17:38
顶 ~~~~ 正好用上  感谢楼主   
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 20:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表