新建JNI项目

2024/07/07

以2021.2.1 patch2版本的Android Studio为例。

1、新建Native C++项目,在之后的选择中选C++11,之后确认,成功创建项目。

2、在main文件夹下,新建jniLibs文件夹,并将.so库放进去。注意:在生产环境中,不必将每一种cpu架构的.so库都放进来,选一种即可。

3、将inc文件夹中的头文件复制进来。

4、在Cmake中集成。

4.1include_directories导入头文件

4.2add_library生成动态库,例libvoicechange.so

#库名的规则: lib + 名称 + .so   (lib .so 系统自动拼接的)
add_library( # Sets the name of the library.
        voicechange  #libvoicechange.so

        SHARED #表示动态库    STATIC 表示静态库.静态库的格式是.a

        native-lib.cpp
        # ${allCPP}  # 批量导入
        )

4.3 生成的这个动态库libvoicechange.so,最终就可以在Java的MainActivity中来查找加载并引用了。

public class JavaMainActivity extends AppCompatActivity{
    static{
        System.loadLibrary("voicechange");
    }
}

2024/07/28 

4.4 find_library() 会查找日志库,把H:\Android\sdk\ndk\21.0.6113669\platforms\android-21\arch-arm\usr\lib中的liblog.so拿过来用,就能打印日志了。

同时还会把liblog.so赋值给变量m-lib。

# 相当于 var log-lib = log (liblog.so 库的路径)
find_library( # Sets the name of the path variable.
        m-lib # 变量名

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        # 这里就相当于 定位到ndk的 liblog.so 库的路径
        log  #查找NDK的日志打印库
        )

4.5 然后把m-lib这个变量拿到target_link_libraries()中进行链接,即链接具体库。(如果学过Linux编程的话会发现,是有链接这个过程的)。

        链接之后就会生成最终的目标,即在MainActivity中引用的那个。

target_link_libraries( # Specifies the target library.
        derryvoicechangeprac2

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

4.6 链接完log库之后,再链接fmod和fmodL

5、搭建界面,编写Java代码。

6、把fmod.jar复制到libs文件夹下(不要忘了在gradle中声明jar包的引入),然后初始化:

    FMOD.init(this);

同时,有init()就有close(),不要忘记在onDestroy中:

    FMOD.close();

7、声明native函数:

    private native void voiceChangeNative(int modeNormal, String path);

8、不使用enter键,手动生成JavaMainActivity的头文件。

8.1、  右击app\src\main\java文件夹,在openIn中选择 (Open In)Terminal,然后使用javah命令生成头文件。

Windows PowerShell
版权所有 (C) Microsoft Corporation。保留所有权利。

尝试新的跨平台 PowerShell https://aka.ms/pscore6

PS I:\AndroidProjects\202407\DerryVoiceChangePrac22\app\src\main\java> javah com.example.derryvoicechangeprac2.JavaMainActivity
错误: 编码GBK的不可映射字符

2024/07/30

9、在javah生成的头文件中引入fmod的头文件:

#include "fmod.hpp"  //fmod的头文件

 10、CmakeList.txt中导入头文件和库文件:

# TODO 第一步:导入头文件
include_directories(inc) # CMakeLists.txt 目录下的inc文件夹 放头文件

# TODO 第二步:导入库文件(C++的环境变量)- 最新的方法,以前是 add_xxx(已淘汰)6.0以下才可以
# 环境变量的添加是追加的方式的:%JAVA_HOME%;%ANDROID_HOME%;path1;path2;
# CMAKE_SOURCE_DIR:获得当前CmakeLists.txt的路径
# CMAKE_ANDROID_ARCH_ABI:自动获取 四大平台架构值  也可以在gradle里面进行指定
# 这个set的写法就相当于  path = path + CMAKE_CXX_FLAGS;
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")

11、把生成的头文件移动到 app\src\main\cpp 文件夹下。这里的头文件只是一个声明,还需要继续写实现。

#include "com_example_derryvoicechangeprac2_JavaMainActivity.h"

using namespace FMOD;//命名空间

//extern "C" 表示必须采用c的标准。原因:1、因为c语言不允许函数重载,如果不写extern "C"关键字,会出现c++函数重载,就会造成混乱,出现bug(当初把一个很简单的java函数名,
//                                 写成这么长一串,就是为了避免重载)
//                                  2、JNIEnv的里面所有的函数指针,都是采用的c的标准,所以必须明确是c的定义方式extern "C"。
//JNIEXPORT表示对外暴露JNI
//JNICALL是表示这是一个jni函数的一个标记
extern "C" JNIEXPORT void JNICALL Java_com_example_derryvoicechangeprac2_JavaMainActivity_voiceChangeNative
    (JNIEnv * env, jobject thiz, jint mode, jstring path){
    char * content = "默认,播放完毕";//相当于Java的字符串String
    //Java是万物皆对象,c是万物皆指针
    //把 JNIEnv里的几百个函数指针玩透,jni就过关了
    //jstring转换成char*
    const char* path_ = env->GetStringUTFChars(path, NULL);
    System * system = 0;//fmod音效引擎系统
    Sound * sound = 0;//fmod声音
    Channel * channel = 0;//通道 音轨
    DSP * dsp = 0;//数字信号处理(digital signal process)

    //第一步 创建系统。执行完后,system就有丰富的值了
    System_Create(&system); //因为参数是二级指针,所以要用&再次取出指针所对应的地址
    //第二步 系统的初始化,32是最大的音轨数
    system->init(32,FMOD_INIT_NORMAL,0);
    //第三步 创建声音,最重要的环节是把声音在音轨上播放,需要把声音初始化,如果声音是空指针肯定不行
    system->createSound(path_, FMOD_DEFAULT, 0, &sound);
    //第四步 播放声音
    system->playSound(sound, 0, false, &channel);


    bool isPlay = true;
    while(isPlay){
    channel->isPlaying(&isPlay);//只有通道最清楚有没有播放完成,如果通道播放完成,会自动修改isPlay地址所对应的
    // 值为false,跳出循环,走到后面释放资源的步骤
    usleep(1000*30); // 休眠30毫秒
    }

    // 好习惯:释放资源
    dsp->release();
    sound->release();
    system->close();
    system->release();
    env->ReleaseStringUTFChars(path, path_);
}

 12、build.gradle中

externalNativeBuild{
            cmake{
                // cppFlags "" // 这样写,默认是支持四大平台

                // 指定CPU架构是armeabi-v7a
                // 指定CMakeLists.txt里面的环境变量CMAKE_ANDROID_ARCH_ABI的值
                // 【注意:这里只指定本地库到armeabi-v7a, x86】 这句代码 还不能决定apk生成
                abiFilters ("armeabi-v7a", "x86","x86_64")
            }

            // TODO 第五步:指定CPU的架构  apk/lib/平台
            // 下面代码不写,默认是四大CPU架构平台
            ndk{
                // 指定CPU架构是armeabi-v7a, x86
                // 【注意:这里只指定编译所有库到armeabi-v7a, x86 进apk】
                abiFilters ("armeabi-v7a", "x86","x86_64")
            }
        }


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值