吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7454|回复: 45
收起左侧

[Android 原创] 折腾折腾用android studio去编写so--动态注册

  [复制链接]
欧雨鹏 发表于 2020-10-23 01:32
本帖最后由 欧雨鹏 于 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

d1

d1

d2

d2

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

d4

d4

代码如下:
[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
因为懒得搞布局,把辅助线添加,拉一拉界线。免得运行控件全跑了。(惨痛的教训)

d15

d15

d16.png

这样,控件就设置完成了,界面也算做好了。
下面开始写代码,在MainActivity类里进行初始化和计算操作
先对控件做一个初始化.

d6

d6

代码如下:
[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层

d8

d8


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

生成h文件。

d9

d9


创建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

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

d10

d10

在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,添加了又给出这个警告。不知道怎么解决。

d11

d11
so文件顺利生成。顺便查看了一下AndroidManifest.xml
[Asm] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application
        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">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

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

d12

d12

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

d13

d13
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又出现报错

d14

d14

[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 d17.png
运行效果如下:

d18

d18



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

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

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

ns1

ns1


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

ns2

ns2

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

ns3

ns3



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

这又过了一天。昨天写的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以后再去补充。
运行效果如下:

add

add

sub

sub

div

div

mul

mul


这整个过程就算是完成了。
总结一下:
动态注册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。

d5

d5

d7

d7

免费评分

参与人数 10威望 +1 吾爱币 +28 热心值 +10 收起 理由
li13893538131 + 1 + 1 谢谢@Thanks!
北笙ぐ + 1 + 1 用心讨论,共获提升!
shizi1521 + 1 + 1 谢谢@Thanks!
fengbolee + 1 + 1 用心讨论,共获提升!
hack_wangyu + 1 + 1 用心讨论,共获提升!
锋霜 + 1 + 1 热心回复!
jing5460 + 1 我很赞同!
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
笙若 + 1 + 1 谢谢@Thanks!
duhao1027 + 1 + 1 用心讨论,共获提升!

查看全部评分

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

Destroyer 发表于 2020-10-24 21:23
贝优妮塔 发表于 2020-10-23 10:47
写so居然这么麻烦
比C++写dll 麻烦多了   
没怎么玩过java

so 约等于 dll  so是在Android 平台运行的(linux也行),dll 是在window平台运行的,他这个只是借助Android studio来写so, linux可以直接写,用不了这么麻烦,只是Android 开发一般会用Android studio来写,方便和Android程序一起调试

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
贝优妮塔 + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| 欧雨鹏 发表于 2020-10-23 13:24
小骚 发表于 2020-10-23 08:42
那么问题来了.........为啥要用代码生成h或者cpp.......右键新建一个或者直接改后缀貌似都可以的吧........ ...

没问题的。目前写的只是没用到h文件。用javah命令创建h文件是,因为省去了再去写代码的步骤。目前的例子没用到h文件,其实不创建h文件也可以的。直接创建个.c或者.cpp把代码写进去就好。android studio中的Native C++项目,自动创建的就只有cpp文件,没有h文件。可见h文件不是必须的。
美美木耶 发表于 2020-10-23 02:14
Agnehc 发表于 2020-10-23 05:54
有电复杂
dyyy 发表于 2020-10-23 07:13
有些看不明白,慢慢看,感谢分享
小骚 发表于 2020-10-23 08:42
那么问题来了.........为啥要用代码生成h或者cpp.......右键新建一个或者直接改后缀貌似都可以的吧.............我用着好像没毛病 QQ图片20201023084130.png
贝优妮塔 发表于 2020-10-23 10:47
小骚 发表于 2020-10-23 08:42
那么问题来了.........为啥要用代码生成h或者cpp.......右键新建一个或者直接改后缀貌似都可以的吧........ ...

写so居然这么麻烦
比C++写dll 麻烦多了   
没怎么玩过java
一直认为so=dll的
roc2030 发表于 2020-10-23 10:49
楼主威武!厉害厉害
xjcyxyx 发表于 2020-10-23 11:22
好复杂啊
老柴头 发表于 2020-10-23 11:44
楼主厉害!
xiaoaiai2468 发表于 2020-10-23 13:13
感谢大佬的分享,学习学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-24 19:13

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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