android的动态注册,折腾折腾用android studio去编写so--动态注册

本帖最后由 欧雨鹏 于 2020-10-23 22:02 编辑

静态注册C方法:https://www.52pojie.cn/thread-1288308-1-1.html

序言

因为android studio版本我给升级到4.1。有些以前的操作可能无法进行完整的操作。

之前在搜索资料的时候,看到一位前辈提到,除了cmake,还可以ndk-build。

现在重新进行一次操作。动态注册c/c++,代码量比静态注册C比较多。

分两步过程 :先把代码码一遍。再一次性生成操作。

一、创建jni类,生成h和实现native,绑定注册

1.创建jni类,添加native方法

在src/main/java/com.example.myapplication里面创建 java类,操作:选中com.example.myapplication,右键,New---Java Class.

这里取的类名为:lstnjisuan

55fd2b2273b5a8b4531f72773c469d6e.gif

d1.png (45.04 KB, 下载次数: 0)

d1

2020-10-22 17:12 上传

55fd2b2273b5a8b4531f72773c469d6e.gif

d2.png (12.61 KB, 下载次数: 1)

d2

2020-10-22 17:12 上传

添加native方法,为loadLibrary设置名称

55fd2b2273b5a8b4531f72773c469d6e.gif

d4.png (47.97 KB, 下载次数: 1)

d4

2020-10-22 17:29 上传

代码如下:

[Java] 纯文本查看 复制代码package com.example.myapplication;

public class lstnjisuan {

static{

System.loadLibrary("funjisuan");//设置so名称

}

public native float add(float firstnumber,float secondnumber);//加法方法

public native float sub(float firstnumber,float secondnumber);//减法方法

public native float mul(float firstnumber,float secondnumber);//剩法方法

public native float div(float firstnumber,float secondnumber);//除法方法

}

然后先把MainActivity里的调用方法写完,后面就不会再来写了。

先给界面拖几个控件,设置 一下id

控件为:2个 plain text,4个button,1个textview

用于输入的两个plain text ,id分别为:numbertext1,numbertext2

5个button 用于选 择加减乘除,计算按钮,id分别为addbutton,subbutton,mulbutton,divbutton

1个textview控件用于显示结果,id为:sumtextview

因为懒得搞布局,把辅助线添加,拉一拉界线。免得运行控件全跑了。(惨痛的教训)

55fd2b2273b5a8b4531f72773c469d6e.gif

d15.png (15.38 KB, 下载次数: 2)

d15

2020-10-23 00:38 上传

55fd2b2273b5a8b4531f72773c469d6e.gif

d16.png (68.59 KB, 下载次数: 0)

2020-10-23 00:41 上传

这样,控件就设置完成了,界面也算做好了。

下面开始写代码,在MainActivity类里进行初始化和计算操作

先对控件做一个初始化.

55fd2b2273b5a8b4531f72773c469d6e.gif

d6.png (98.55 KB, 下载次数: 2)

d6

2020-10-22 17:54 上传

代码如下:

[Java] 纯文本查看 复制代码package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

private Button add;//这五个按钮用于获取id和进行监听

private Button sub;

private Button mul;

private Button div;

private EditText first;//用来获取输入两个操作数

private EditText second;

private TextView result;//用来转换后输出到textview显示结果的变量

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

contextinIt();

}

private void contextinIt()

{

first=findViewById(R.id.numbertext1);

second=findViewById(R.id.numbertext2);

add=(Button) findViewById(R.id.addbutton);

sub=(Button) findViewById(R.id.subbutton);

mul=(Button) findViewById(R.id.mulbutton);

div=(Button) findViewById(R.id.divbutton);

result=findViewById(R.id.sumtextview);

}

}

findViewById这个函数有什么 作用?

定位函数,主要是引用.R文件里的引用名。一般在R.java文件里系统会自动帮你给出你在XML里定义的ID或者Layout里面的名称。

接着设置button监听计算.

完整代码如下:

[Java] 纯文本查看 复制代码package com.example.myapplication9;

import androidx.appcompat.app.AppCompatActivity;

import android.view.View.OnClickListener;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

private Button add;//这四个按钮用于获取id和进行监听

private Button sub;

private Button mul;

private Button div;

private EditText first;//用来获取输入两个操作数

private EditText second;

private TextView result;

private float oneNumber;//临时变量,用于计算和获取结果

private float twoNumber;

private float resultsum=0;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

controlinIt();

add.setOnClickListener(onls);

sub.setOnClickListener(onls);

mul.setOnClickListener(onls);

div.setOnClickListener(onls);

}

private void controlinIt()

{

first=findViewById(R.id.numbertext1);

second=findViewById(R.id.numbertext2);

add=(Button) findViewById(R.id.addbutton);

sub=(Button) findViewById(R.id.subbutton);

mul=(Button) findViewById(R.id.mulbutton);

div=(Button) findViewById(R.id.divbutton);

result=(TextView)findViewById(R.id.sumtextview);

}

private OnClickListener onls=new OnClickListener()

{

public void onClick(View v)

{

lstnjisuan ls=new lstnjisuan();

switch (v.getId())

{

case R.id.addbutton:

oneNumber=Float.parseFloat(first.getText().toString());

twoNumber=Float.parseFloat(second.getText().toString());

resultsum=ls.add(oneNumber,twoNumber);

result.setText(Float.toString(resultsum));

break;

case R.id.subbutton:

oneNumber=Float.parseFloat(first.getText().toString());

twoNumber=Float.parseFloat(second.getText().toString());

resultsum=ls.sub(oneNumber,twoNumber);

result.setText(Float.toString(resultsum));

break;

case R.id.mulbutton:

oneNumber=Float.parseFloat(first.getText().toString());

twoNumber=Float.parseFloat(second.getText().toString());

resultsum=ls.mul(oneNumber,twoNumber);

result.setText(Float.toString(resultsum));

break;

case R.id.divbutton:

oneNumber=Float.parseFloat(first.getText().toString());

twoNumber=Float.parseFloat(second.getText().toString());

resultsum=ls.div(oneNumber,twoNumber);

result.setText(Float.toString(resultsum));

break;

default:

break;

}

}

};

}

2.生成h文 件,并创建 c文 件实现,注册和绑定native方法

在main层,创建 一个jni文 件夹,操作:New---Folder---JNI Folder

alt+f12打开terminal,cd 到java层

55fd2b2273b5a8b4531f72773c469d6e.gif

d8.png (41.15 KB, 下载次数: 0)

d8

2020-10-22 18:33 上传

执行javah命令

[Asm] 纯文本查看 复制代码javah -d ../jni com.example.myapplication.lstnjisuan

生成h文件。

55fd2b2273b5a8b4531f72773c469d6e.gif

d9.png (79.98 KB, 下载次数: 1)

d9

2020-10-22 18:44 上传

创建c文件,实现计算,注册和绑定

选中jni文件夹,右键,New---C/C++ Source File,选择文件格式为  .c

这里设置名称为:bindNativeJisuan

实现代码如下:

[C] 纯文本查看 复制代码//

// Created by pady on 2020/10/22.

//

#include "com_example_myapplication_lstnjisuan.h"

JNIEXPORT jfloat JNICALL Java_com_example_myapplication_lstnjisuan_add

(JNIEnv *env, jobject obj, jfloat one, jfloat two)

{

return one+two;

}

JNIEXPORT jfloat JNICALL Java_com_example_myapplication_lstnjisuan_sub

(JNIEnv *env, jobject obj, jfloat one, jfloat two)

{

return one-two;

}

JNIEXPORT jfloat JNICALL Java_com_example_myapplication_lstnjisuan_mul

(JNIEnv *env, jobject obj, jfloat one, jfloat two)

{

return one*two;

}

JNIEXPORT jfloat JNICALL Java_com_example_myapplication_lstnjisuan_div

(JNIEnv *env, jobject obj, jfloat one, jfloat two)

{

return one/two;

}

//绑定java层中native方法

static const JNINativeMethod nativeMethod[]={

{"add","(FF)F",(void**)&Java_com_example_myapplication_lstnjisuan_add},

{"sub","(FF)F",(void**)&Java_com_example_myapplication_lstnjisuan_sub},

{"mul","(FF)F",(void**)&Java_com_example_myapplication_lstnjisuan_mul},

{"div","(FF)F",(void**)&Java_com_example_myapplication_lstnjisuan_div}

};

//注册nativeMethod方法,注册相应的类以及方法

jint registNativeMethod(JNIEnv *env)

{

char* strname="com/example/myapplication9/lstnjisuan";

jclass funclass=(*env)->FindClass(env,"strname");

//进行JAVA层注册,如果不等于0返回错误

if(((*env)-> RegisterNatives(env, funclass,nativeMethod,sizeof(nativeMethod)/sizeof(nativeMethod[0])))!=0)

{

return JNI_ERR;

}

return JNI_OK;

}

//实现JNI_ONLOAD动态注册

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm,void *reserved)

{

JNIEnv *env;

#ifndef JNI_VERSION_1_4

if((*jvm)->GetEnv(jvm,(void**)&env,JNI_VERSION_1_4)!=JNI_OK)

{

return JNI_ERR;

}

if(registNativeMethod(env)!=JNI_OK)

{

return JNI_ERR;

}

return JNI_VERSION_1_4;

#endif

if((*jvm)->GetEnv(jvm,(void**)&env,JNI_VERSION_1_6)!=JNI_OK)

{

return JNI_ERR;

}

if(registNativeMethod(env)!=JNI_OK)

{

return JNI_ERR;

}

return JNI_VERSION_1_6;

}

讲解:

JNINativeMethod 这是个结构体,在jni.h中定义。结构体如下:

[C] 纯文本查看 复制代码/*

* used in RegisterNatives to describe native method name, signature,

* and function pointer.

*/

typedef struct {

char *name;

char *signature;

void *fnPtr;

} JNINativeMethod;上面有提到的,三个参数,name是java类中的native方法名,第二个参数是签名,就是指参数和返回值,最后是对应C函数的地址比如上面看到的"(FF)F",F是什么呢?是Smali语法的数据类型,F是float类型。括号里面两个FF,指明有两个float参数,外面的F,指明返回值是float.其它数据类型请查看smali语法。jint是什么?就是int类型。请看jni.h文件就明白了。上面很多函数都可以在jni.h文件中查看声明定义。可在jdk版本的include文件夹里找到jni.h文件。

上面除了计算实现的函数,其它的一列系操作最后就是主要被jni_onload函数调用的。代码都写好了。现在开始生成so文件。

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

二、用ndk-build生成so操作(这一部分可不看,是旧版的操作,因为操作没有成功。采用CMake,请直接往下拉到第三部分看正常生成的操作。。)

这一段是不成功的操作,生成配置写在.mk文件里。折腾了一天都没成功。不知道是什么原因。1.在jni文件夹里,创建两个文件:android.mk和application.mk操作:New---File,直接输入android.mk .再次New---File,直接输入application.mk选中android.mk,输入以下内容

[C] 纯文本查看 复制代码LOCAL_PATH:=$(call my-dir) #开头必须定义的LOCAL_PATH,my-dir是宏函数,用来返回android.mk所在目录的路径

include $(CLEAR_VARS) #负责清除LOCAL_ 变量,除了path

LOCAL_MODULE:=funjisuan #模块名称,就是生成so的名称,和loadlibrary设置的名称一致

LOCAL_SRC_FILES:=Cfunjisuan.c #C源文件

include $(BUILD_SHARED_LIBRARY) #设置动态链接

application.mk内容如下:

[Asm] 纯文本查看 复制代码APP_ABI :=all

APP_PLATFORM:=android-16

生成支持的所有版本如下图:

55fd2b2273b5a8b4531f72773c469d6e.gif

d10.png (68.35 KB, 下载次数: 1)

d10

2020-10-22 19:33 上传

在terminal里cd 到jni层,就可以直接ndk-build了。操作方法:ndk-build

出现一个警告:

[Asm] 纯文本查看 复制代码Android NDK: WARNING: APP_PLATFORM android-16 is higher than android:minSdkVersion 1 in E:/DownLoad/MyApplication8/app/src/main/AndroidManifest.xml. NDK binaries will *not* be compatible with de

vices older than android-16. See https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md for more information.不添加就提示默认为android-16,添加了又给出这个警告。不知道怎么解决。

55fd2b2273b5a8b4531f72773c469d6e.gif

d11.png (68.97 KB, 下载次数: 0)

d11

2020-10-22 20:12 上传

so文件顺利生成。顺便查看了一下AndroidManifest.xml

[Asm] 纯文本查看 复制代码<?xml version="1.0" encoding="utf-8"?>

package="com.example.myapplication">

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:roundIcon="@mipmap/ic_launcher_round"

android:supportsRtl="true"

android:theme="@style/Theme.MyApplication">

搜索WARNING: APP_PLATFORM android-16 is higher than android:minSdkVersion 1 ,大多说要把build/core/add-application.mk中的__ndk-warning改成__ndk_info改了依然警告.不管它了。查看生成的情况。发现在main层生成libs和obj

55fd2b2273b5a8b4531f72773c469d6e.gif

d12.png (51.37 KB, 下载次数: 1)

d12

2020-10-22 20:41 上传

最后一步,直接Rebuild Project。这一步操作是成功的。查看一下生成的APK.

55fd2b2273b5a8b4531f72773c469d6e.gif

D13.png (50.91 KB, 下载次数: 1)

d13

2020-10-22 20:45 上传

so文件没有打包进去,也就是lib文件生成的各个版本的so没有打包进去。这种APK安装后是无法运行的。因为加载不到so文件。需要在build.gradle中设置ndkbuild?那么在build.gradle设置一下:在defaultConfig 节点里面添加下面代码:

[Asm] 纯文本查看 复制代码externalNativeBuild{

ndkBuild{

arguments "NDK_APPLICATION_MK:=src/main/jni/application.mk"

cFlags "-DTEST_C_FLAGS1","-DTEST_C_FLAG2"

cppFlags "-DTEST_CPP_FLAGS1","-DTEST_CPP_FLAG2"

}

}

在andoird节点添加下面代码:

[Asm] 纯文本查看 复制代码externalNativeBuild {

ndkBuild {

path file('src/main/jni/android.mk')

}

}

完整代码如下:

[Asm] 纯文本查看 复制代码plugins {

id 'com.android.application'

}

android {

compileSdkVersion 30

buildToolsVersion "30.0.2"

defaultConfig {

applicationId "com.example.myapplication"

minSdkVersion 22

targetSdkVersion 30

versionCode 1

versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

externalNativeBuild{

ndkBuild{

arguments "NDK_APPLICATION_MK:=src/main/jni/application.mk"

cFlags "-DTEST_C_FLAGS1","-DTEST_C_FLAG2"

cppFlags "-DTEST_CPP_FLAGS1","-DTEST_CPP_FLAG2"

}

}

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

}

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

externalNativeBuild {

ndkBuild {

path file('src/main/jni/android.mk')

}

}

}

dependencies {

implementation 'androidx.appcompat:appcompat:1.2.0'

implementation 'com.google.android.material:material:1.2.1'

implementation 'androidx.constraintlayout:constraintlayout:2.0.2'

testImplementation 'junit:junit:4.+'

androidTestImplementation 'androidx.test.ext:junit:1.1.2'

androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

}

再次执行ReBuild Project又出现报错

55fd2b2273b5a8b4531f72773c469d6e.gif

d14.png (83.49 KB, 下载次数: 1)

d14

2020-10-22 20:59 上传

[Asm] 纯文本查看 复制代码D:/SDK/ndk/21.1.6352462/build//../build/core/build-module.mk:34: *** Android NDK: Assertion failure: LOCAL_MAKEFILE is not defined . Stop.

executing external native build for ndkBuild E:\DownLoad\MyApplication8\app\src\main\jni\android.mk提示LOCAL_MAKEFILE is not defined。什么玩意?这个LOCAL_MAKEFILE是什么?找到build/core/build-module.mk,打开一看。

[C] 纯文本查看 复制代码#

$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))

$(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))

# This file is used to record the LOCAL_XXX definitions of a given

# module. It is included by BUILD_STATIC_LIBRARY, BUILD_SHARED_LIBRARY

# and others.

#

LOCAL_MODULE_CLASS := $(strip $(LOCAL_MODULE_CLASS))

ifndef LOCAL_MODULE_CLASS

$(call __ndk_info,$(LOCAL_MAKEFILE):$(LOCAL_MODULE): LOCAL_MODULE_CLASS definition is missing !)

$(call __ndk_error,Aborting)

endif

$(if $(call module-class-check,$(LOCAL_MODULE_CLASS)),,\

$(call __ndk_info,$(LOCAL_MAKEFILE):$(LOCAL_MODULE): Unknown LOCAL_MODULE_CLASS value: $(LOCAL_MODULE_CLASS))\

$(call __ndk_error,Aborting)\

)

$(call module-add,$(LOCAL_MODULE))

# Eval sucks. It's not possible to preserve even properly escaped # characters

# as far as I can tell, and we need that for -Werror=#warnings. Manually stash

# all the flags variations so we can preserve these.

__ndk_modules.$(LOCAL_MODULE).ASFLAGS := $(LOCAL_ASFLAGS)

__ndk_modules.$(LOCAL_MODULE).ASMFLAGS := $(LOCAL_ASMFLAGS)

__ndk_modules.$(LOCAL_MODULE).CFLAGS := $(LOCAL_CFLAGS)

__ndk_modules.$(LOCAL_MODULE).CLANG_TIDY_FLAGS := $(LOCAL_CLANG_TIDY_FLAGS)

__ndk_modules.$(LOCAL_MODULE).CONLYFLAGS := $(LOCAL_CONLYFLAGS)

__ndk_modules.$(LOCAL_MODULE).CPPFLAGS := $(LOCAL_CPPFLAGS)

__ndk_modules.$(LOCAL_MODULE).CXXFLAGS := $(LOCAL_CXXFLAGS)

__ndk_modules.$(LOCAL_MODULE).LDFLAGS := $(LOCAL_LDFLAGS)

__ndk_modules.$(LOCAL_MODULE).RENDERSCRIPT_FLAGS := $(LOCAL_RENDERSCRIPT_FLAGS)于是折腾了很久,最后android.mk改成这样。

[Asm] 纯文本查看 复制代码LOCAL_PATH:=$(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS:=optional

LOCAL_MODULE:=funjisuan

LOCAL_SRC_FILES:=bindNativeJisuan.c

LOCAL_MODULE_CLASS:=SHARED_LIBRAYIES

include $(BUILD_SHARED_LIBRARY)重新ndk-build正常生成so.接着继续ReBuild Project又报错了:

[Asm] 纯文本查看 复制代码Execution failed for task ':app:generateJsonModelDebug'.

> executing external native build for ndkBuild E:\DownLoad\MyApplication8\app\src\main\jni\android.mk得,卡在这一步了。查了半天,都说要降低cmake版本。这是不可能的事了。。果断放弃。

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

删除操作,后面再开始cmakebuild.gradle设置中删除下面这条设置

[Asm] 纯文本查看 复制代码externalNativeBuild{

ndkBuild{

arguments "NDK_APPLICATION_MK:=src/main/jni/application.mk"

cFlags "-DTEST_C_FLAGS1","-DTEST_C_FLAG2"

cppFlags "-DTEST_CPP_FLAGS1","-DTEST_CPP_FLAG2"

}

}

删除下面这条设置externalNativeBuild {

ndkBuild {

path file('src/main/jni/android.mk')

}

}再删除除android.mk,删除application.mk点一下sync now

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

三、用CMake生成SO

ndk-build果断玩不动。还是继续CMAKE

在gradle.properties中,添加下面这条:

[Asm] 纯文本查看 复制代码ndk{

moduleName "funjisuan"

}

在app层里的build.gradle中,android节点的设置。defaultConfig节点中添加下面内容:

[Asm] 纯文本查看 复制代码externalNativeBuild{

cmake{

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

}

}

defaultConfig节点外面,android节点里面添加下面内容:

[Asm] 纯文本查看 复制代码externalNativeBuild{

cmake{

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

}

}

完整设置如下:

[Asm] 纯文本查看 复制代码android {

compileSdkVersion 30

buildToolsVersion "30.0.2"

defaultConfig {

applicationId "com.example.myapplication"

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文件

}

}

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

}

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

externalNativeBuild{

cmake{

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

}

}

}

在app层,新建CMakeLists.txt文件,操作:选中app,右键,New---FileCMakeLists.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文件名称.

funjisuan

# Sets the library as a shared library.

SHARED

# 设置这个so文件为共享.

# Provides a relative path to your source file(s).

# 设置这个so文件为共享.

src/main/jni/bindNativeJisuan.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.

# 制定目标库.

funjisuan

# Links the target library to the log library

# included in the NDK.

${log-lib} )

好了就可以直接点上面的Build----Rebuild project

55fd2b2273b5a8b4531f72773c469d6e.gif

d17.png (100.5 KB, 下载次数: 1)

2020-10-23 01:04 上传

运行效果如下:

55fd2b2273b5a8b4531f72773c469d6e.gif

d18.png (33.48 KB, 下载次数: 0)

d18

2020-10-23 01:06 上传

总结:动态注册中,native方法不是static,C方法中,需要用JNI_onLoad注册。后面生成so的操作过程是一样的。之前操作的直接返回一个static方法(返回字符串).最后还是用CMAKE生成SO。现在比较新的android studio版本,可以创建Native C++,只需要把C++层代码写一写就可以直接生成了。之所以搞这么老的操作,是想理解这个过程。以后写这种代码肯定直接创建Native C++项目。不必再这样折腾。

最后,不得不说的一句,代码逻辑有问题。点击计算按钮就闪退了。搞不动。睡觉。。

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

现在编写SO创建Native C++项目。

55fd2b2273b5a8b4531f72773c469d6e.gif

ns1.png (51.37 KB, 下载次数: 0)

ns1

2020-10-23 13:36 上传

Next,设置好项目名称,再Next ,选择C++标准。再点击finish就完成创建.

55fd2b2273b5a8b4531f72773c469d6e.gif

ns2.png (43.71 KB, 下载次数: 1)

ns2

2020-10-23 13:38 上传

完了项目已经自动生成cpp文件,CMakeLists.txt。需要改动的地方就三个文件,MainActivity类里,因为system.loadlibrary写在这里,需要修改so名称直接在这里改。cpp文件名称可直接修改,然后实现代码完好。CMakeLists.txt,需要修改一下cpp被修改后的名称,还有LoadLibrary修改后的名称。就可以直接Build了。

55fd2b2273b5a8b4531f72773c469d6e.gif

ns3.png (77.86 KB, 下载次数: 0)

ns3

2020-10-23 13:47 上传

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

这又过了一天。昨天写的C代码居然因为一个字母导致异常退出了。

经过数次的调试,原来是c文件在FindClass时,写错了类文件名称。导致找不到jni类.所以再来修改一下。修改的地方是:

[C] 纯文本查看 复制代码jint registNativeMethod(JNIEnv *env)

{

char* strname="com/example/myapplication9/lstnjisuan";

jclass funclass=(*env)->FindClass(env,"strname");

//进行JAVA层注册,如果不等于0返回错误

if(((*env)-> RegisterNatives(env, funclass,nativeMethod,sizeof(nativeMethod)/sizeof(nativeMethod[0])))!=0)

{

return JNI_ERR;

}

return JNI_OK;

}

原来写的是:

[C] 纯文本查看 复制代码jclass funclass=(*env)->FindClass(env,"./listnjisuan");

现在改过来了。

简易器计算稍微正常了。没有对输入框对输入的数字进行判断。这种BUG以后再去补充。

运行效果如下:

55fd2b2273b5a8b4531f72773c469d6e.gif

ns4.png (22.79 KB, 下载次数: 0)

add

2020-10-23 21:49 上传

55fd2b2273b5a8b4531f72773c469d6e.gif

ns5.png (33.96 KB, 下载次数: 0)

sub

2020-10-23 21:49 上传

55fd2b2273b5a8b4531f72773c469d6e.gif

ns7.png (33.9 KB, 下载次数: 2)

div

2020-10-23 21:49 上传

55fd2b2273b5a8b4531f72773c469d6e.gif

ns6.png (34.01 KB, 下载次数: 1)

mul

2020-10-23 21:49 上传

这整个过程就算是完成了。

总结一下:

动态注册C就是通过JNI_onLoad来完成。在android的jni文档里有示例。h文件生不生成其实没关系,至少目前没关系,因为都在C文件实现了。只不过写C语言写习惯了,总会写个h文件进行声明。

上面提到的生成so方法两种:

1.把CMakeLists.txt文件设置完,build.gradle,还有build.properties设置一下,整个代码写完可以直接build就可以了。过程不算复杂。

2.不要创建默认的空项目,或者hello项目,选择Native C++项目,cpp代码写好,native代码写好。直接修改CMakeLists.txt的内容,cpp名称,so名称,就可以直接Build。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值