Gluon Mobile iOS 音频播放器

Gluon Mobile iOS Audio Player

由于 JavaFx Media 尚未移植到移动平台,任何人都可以帮助我使用本机 iOS APi 来播放将存储在中的声音 mp3 文件我的 gluon 项目中的 main/resources 文件夹。

虽然在 Android 上,我们可以轻松地将本机 API 添加到 Gluon 项目的 Android 文件夹中(检查此 solution 以在 [=131] 上使用本机媒体=]), 使用本机代码 (Objetive-C) 和 iOS 文件夹上的媒体 API 是不够的,因为它必须被编译,并且编译后的文件必须包含在ipa.

目前,Charm Down is doing this for a bunch of services. If you have a look at the build.gradle script for iOS,它包括 xcodebuild 编译和构建本机库 libCharm.a 的任务,以后应该包含在任何 iOS 项目中使用任何这些服务。

我的建议是克隆 Charm Down,并提供一项新服务:AudioService,以及一些基本方法,例如:

public interface AudioService {
    void play(String audioName);
    void pause();
    void resume();
    void stop(); 
}

此服务将添加到 Platform class:

public abstract class Platform {
    ...
    public abstract AudioService getAudioService();
}

并且您应该为桌面(空)、Android(如 here)和 iOS.

提供实现

IOS 实施 - Java

您必须将此添加到 IOSPlatform class:

public class IOSPlatform extends Platform {
    ...
    @Override
    public AudioService getAudioService() {
        if (audioService == null) {
            audioService = new IOSAudioService();
        }
        return audioService;
    }
}

并创建 IOSAudioService class:

public class IOSAudioService implements AudioService {

    @Override
    public void play(String audioName) {
        CharmApplication.play(audioName);
    }

    @Override
    public void pause() {
        CharmApplication.pause();
    }

    @Override
    public void resume() {
        CharmApplication.resume();
    }

    @Override
    public void stop() {
        CharmApplication.stop();
    }
}

最后,您必须在 CharmApplication 中添加本机调用:

public class CharmApplication {
    static {
        System.loadLibrary("Charm");
        _initIDs();
    }
    ...
    public static native void play(String audioName);
    public static native void pause();
    public static native void resume();
    public static native void stop();
}

IOS 实施 - Objective-C

现在,在本机文件夹 CharmApplication.m 上,添加这些调用的实现:

#include "CharmApplication.h"
...
#include "Audio.h"

// Audio
Audio *_audio;

JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_ios_CharmApplication_play
(JNIEnv *env, jclass jClass, jstring jTitle)
{
    NSLog(@"Play audio");
    const jchar *charsTitle = (*env)->GetStringChars(env, jTitle, NULL);
    NSString *name = [NSString stringWithCharacters:(UniChar *)charsTitle length:(*env)->GetStringLength(env, jTitle)];
    (*env)->ReleaseStringChars(env, jTitle, charsTitle);

    _audio = [[Audio alloc] init];
    [_audio playAudio:name];
    return;
}

JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_ios_CharmApplication_pause
(JNIEnv *env, jclass jClass)
{
    if (_audio) 
    {
        [_audio pauseAudio];
    }
    return;   
}

JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_ios_CharmApplication_resume
(JNIEnv *env, jclass jClass)
{
    if (_audio) 
    {
        [_audio resumeAudio];
    }
    return;   
}

JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_ios_CharmApplication_stop
(JNIEnv *env, jclass jClass)
{
    if (_audio) 
    {
        [_audio stopAudio];
    }
    return;   
}

并创建头文件Audio.h:

#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>

@interface Audio :UIViewController <AVAudioPlayerDelegate>
{
}
    - (void) playAudio: (NSString *) audioName;
    - (void) pauseAudio;
    - (void) resumeAudio;
    - (void) stopAudio;
@end

和实施 Audio.m。这个是基于这个 tutorial:

#include "Audio.h"
#include "CharmApplication.h"

@implementation Audio 

AVAudioPlayer* player;

- (void)playAudio:(NSString *) audioName 
{
    NSString* fileName = [audioName stringByDeletingPathExtension];
    NSString* extension = [audioName pathExtension];

    NSURL* url = [[NSBundle mainBundle] URLForResource:[NSString stringWithFormat:@"%@",fileName] withExtension:[NSString stringWithFormat:@"%@",extension]];
    NSError* error = nil;

    if(player)
    {
        [player stop];
        player = nil;
    }

    player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    if(!player)
    {
        NSLog(@"Error creating player: %@", error);
        return;
    }
    player.delegate = self;
    [player prepareToPlay];
    [player play];

}

- (void)pauseAudio
{
    if(!player)
    {
        return;
    }
    [player pause];
}

- (void)resumeAudio
{
    if(!player)
    {
        return;
    }
    [player play];
}

- (void)stopAudio
{
    if(!player)
    {
        return;
    }
    [player stop];
    player = nil;
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    NSLog(@"%s successfully=%@", __PRETTY_FUNCTION__, flag ? @"YES"  : @"NO");
}

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
    NSLog(@"%s error=%@", __PRETTY_FUNCTION__, error);
}

@end

构建本机库

编辑 iOS 模块的 build.gradle,并将音频服务添加到 xcodebuild 任务:

def nativeSources = ["$project.projectDir/src/main/native/CharmApplication.m",
                     ...,
                     "$project.projectDir/src/main/native/Audio.m"]

...
def compileOutputs = [
                "$project.buildDir/native/$arch/CharmApplication.o",
                "$project.buildDir/native/$arch/Charm.o",
                 ...,
                "$project.buildDir/native/$arch/Audio.o"]

构建项目

保存项目,并从 Charm Down 项目的根目录,在命令行 运行:

./gradlew clean build

如果一切正常,您应该:

  • Common/build/libs/charm-down-common-2.1.0-SNAPSHOT.jar
  • Desktop/build/libs/charm-down-desktop-2.1.0-SNAPSHOT.jar
  • Android/build/libs/charm-down-android-2.1.0-SNAPSHOT.jar
  • IOS/build/libs/charm-down-ios-2.1.0-SNAPSHOT.jar
  • IOS/build/native/libCharm.a

Gluon 项目

有了这些依赖项和本机库,您将能够创建一个新的 Gluon 项目,并将 jars 添加为本地依赖项(添加到 libs 文件夹)。

至于原生库,应该添加到这个路径:src/ios/jniLibs/libCharm.a.

更新 build.gradle 脚本:

repositories {
    flatDir {
       dirs 'libs'
   }
    jcenter()
    ...
}

dependencies {
    compile 'com.gluonhq:charm-glisten:3.0.0'
    compile 'com.gluonhq:charm-down-common:2.1.0-SNAPSHOT'
    compile 'com.gluonhq:charm-glisten-connect-view:3.0.0'

    iosRuntime 'com.gluonhq:charm-glisten-ios:3.0.0'
    iosRuntime 'com.gluonhq:charm-down-ios:2.1.0-SNAPSHOT'
}

在您的视图中,检索服务并提供一些基本的 UI 来调用 play("audio.mp3")pause()resume()stop() 方法:

private boolean pause;

public BasicView(String name) {
    super(name);

    AudioService audioService = PlatformFactory.getPlatform().getAudioService();
    final HBox hBox = new HBox(10, 
            MaterialDesignIcon.PLAY_ARROW.button(e -> audioService.play("audio.mp3")),
            MaterialDesignIcon.PAUSE.button(e -> {
                if (!pause) {
                    audioService.pause();
                    pause = true;
                } else {
                    audioService.resume();
                    pause = false;
                }

            }),
            MaterialDesignIcon.STOP.button(e -> audioService.stop()));
    hBox.setAlignment(Pos.CENTER);
    setCenter(new StackPane(hBox));
}

最后,在 src/ios/assets/audio.mp3 下放置一个类似 audio.mp3 的音频文件,构建并部署到 iOS。

希望 Charm Down 能尽快提供这个 API。此外,如果您提出了一个不错的实现,请随时分享并创建一个 Pull Request.