Android-NDK开发之Kotlin与C++类绑定

当你一个Kotlin类里面的所有函数实际执行都需要对应的C\C++函数时,你可能会面临Native层数据共享传递与保存等问题。那有没有一种方法去让Kotlin的实例与C++对象绑定? 我的实现方法是,用动态注册去维护Native层类和Kotlin类的函数映射关系,Native层把对象的指针给到Kotlin层以实现绑定关系。NDK开发之JNI缘起里面介绍过动态注册方法。

下面以一个FFmpeg播放器实现为例(部分代码):

Kotlin类部分

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.qfleng.um.audio

/**
 * FFmpeg播放器
 */
class FFAudioPlayer {

    //C++对应对象的指针
    private var native_instance: Long = 0
    private external fun nCreate(): Long
    private external fun nPlay(ptr: Long)
    private external fun nStop(ptr: Long)
    private external fun nDestory(ptr: Long)

    init {
        native_instance = nCreate()
    }

    fun play() {
        nPlay(native_instance)
    }

    fun destory() {
        nDestory(native_instance)
    }

    fun stop() {
        nStop(native_instance)
    }


}

C++部分代码

.h文件内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//
// Created by Duke
//

#ifndef UM_AUDIOPLAYER_H
#define UM_AUDIOPLAYER_H

#include <jni.h>
#include "SLAudioPlayer.h"

namespace Unreal {
    class NativeAudioPlayer {
    public:
        //FFmpeg+OpenSLES的播放器实现
        SLAudioPlayer *player = NULL;

    public:
        static jlong s_create(JNIEnv *env, jobject clazz);
        static void s_play(JNIEnv *env, jobject clazz, jlong objHandle);
        static void s_stop(JNIEnv *env, jobject clazz, jlong objHandle);
        static void s_destory(JNIEnv *env, jobject clazz, jlong objHandle);

        NativeAudioPlayer();
        ~NativeAudioPlayer();

        void play();
        void stop();
    };


    //动态注册函数对应关系
    static const JNINativeMethod methods[] = {
            {"nCreate",    "()J",                    (void *) NativeAudioPlayer::s_create},
            {"nPlay",      "(J)V",                   (void *) NativeAudioPlayer::s_play},
            {"nStop",      "(J)V",                   (void *) NativeAudioPlayer::s_stop},
            {"nDestory",   "(J)V",                   (void *) NativeAudioPlayer::s_destory}
    };

    const static char *className = "com/qfleng/um/audio/FFAudioPlayer";
}

#endif //UM_AUDIOPLAYER_H

.cpp实现代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//
// Created by Duke
//

#include "NativeAudioPlayer.h"

using namespace Unreal;

jlong NativeAudioPlayer::s_create(JNIEnv *env, jobject clazz) {
    NativeAudioPlayer *obj = new NativeAudioPlayer();
    return reinterpret_cast<jlong>(obj);
}

void NativeAudioPlayer::s_destory(JNIEnv *env, jobject clazz, jlong objHandle) {
    NativeAudioPlayer *obj = reinterpret_cast<NativeAudioPlayer *>(objHandle);
    if (obj)
        delete obj;
}

void NativeAudioPlayer::s_play(JNIEnv *env, jobject clazz, jlong objHandle) {
    NativeAudioPlayer *obj = reinterpret_cast<NativeAudioPlayer *>(objHandle);
    if (obj) {
        obj->play();
    }
}


void NativeAudioPlayer::s_stop(JNIEnv *env, jobject clazz, jlong objHandle) {
    NativeAudioPlayer *obj = reinterpret_cast<NativeAudioPlayer *>(objHandle);
    if (obj) {
        obj->stop();
    }
}


NativeAudioPlayer::NativeAudioPlayer() {
}

NativeAudioPlayer::~NativeAudioPlayer() {
    if (player)
        delete player;
}

void NativeAudioPlayer::play() {
    player->play();
}

void NativeAudioPlayer::stop() {
    if (player)
        delete player;
}

这样Native层的数据就可以停留在本层,只需要和Kotlin交互需要的数据。Kotlin层的类还可以实例化多个对象,数据互不干扰。

参考

上面的实现方式其实是参考的Android的Bitmap实现。可以阅读Bitmap的源码~

Built with Hugo
主题 StackJimmy 设计