Мобильный аудиоплеер Gluon для iOS

Поскольку JavaFx Media еще не был перенесен на мобильные платформы, может ли кто-нибудь помочь мне с использованием собственного iOS APi для воспроизведения звукового mp3-файла, который будет храниться в моей папке main / resources в моем проекте gluon.


person Aniket Joshi    schedule 30.07.2016    source источник


Ответы (1)


На Android мы можем легко добавить собственный API в папки Android проекта Gluon (проверьте это решение для использования собственного мультимедиа на Android), использования собственного кода (Objetive-C) с Media API в папках iOS недостаточно, так как он должен быть скомпилирован, а скомпилированные файлы быть включенным в ipa.

В настоящее время Charm Down делает это для ряда служб. Если вы посмотрите на сценарий build.gradle для iOS, он включает xcodebuild задачу по компиляции и сборке собственной библиотеки libCharm.a, которая позже должна быть включена в любой проект iOS, использующий любую из этих служб.

Я предлагаю клонировать Charm Down и предоставить новую услугу: AudioService, с некоторыми базовыми методами, такими как:

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

Эта услуга будет добавлена ​​в класс Platform:

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

и вы должны предоставить реализации для Desktop (пустой), Android (например, здесь) и iOS.

Реализация iOS - Java

Вам нужно будет добавить это в класс IOSPlatform:

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

и создайте класс IOSAudioService:

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. Это основано на этом руководстве:

#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

Создайте собственную библиотеку

Отредактируйте build.gradle для модуля iOS и добавьте службу Аудио в задачу 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

Если все в порядке, у вас должно быть:

  • Общий / build / libs / charm-down-common-2.1.0-SNAPSHOT.jar
  • Рабочий стол / build / libs / charm-down-desktop-2.1.0-SNAPSHOT.jar
  • Android / сборка / библиотеки / очарование-вниз-android-2.1.0-SNAPSHOT.jar
  • IOS / build / libs / charm-down-ios-2.1.0-SNAPSHOT.jar
  • IOS / сборка / родной / libCharm.a

Проект Gluon

С этими зависимостями и собственной библиотекой вы сможете создать новый проект Gluon и добавить банки в качестве локальных зависимостей (в папку 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'
}

В вашем представлении извлеките службу и предоставьте базовый интерфейс для вызова методов 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));
}

Наконец, поместите аудиофайл, например audio.mp3, в src/ios/assets/audio.mp3, соберите и разверните в iOS.

Надеюсь, что этот API будет предоставлен Charm Down в ближайшее время. Также, если вы придумали хорошую реализацию, не стесняйтесь поделиться ею и создать Запрос на включение.

person José Pereda    schedule 30.07.2016
comment
После применения всех этих изменений приложение зависло. журнал имеет следующий вывод: 2016-07-30 12: 32: 50.769 GluonApp [3146: 1115803] Воспроизвести звук 2016-07-30 12: 32: 50.770 GluonApp [3146: 1115803] *** NSForwarding: предупреждение: объект 0x1d34b64 из класс 'Audio' не реализует methodSignatureForSelector: - впереди проблемы 2016-07-30 12: 32: 50.770 GluonApp [3146: 1115803] *** NSForwarding: предупреждение: объект 0x1d34b64 класса 'Audio' не реализует doesNotRecognizeSelector: - прервать - person Aniket Joshi; 30.07.2016
comment
Убедитесь, что вы выполнили каждый шаг, есть много файлов, которые нужно изменить. Удалось ли вам успешно построить модифицированный Charm Down? Вы используете iOS sdk 9.3? - person José Pereda; 30.07.2016
comment
Я отредактировал свой ответ, но с небольшими изменениями в Audio.m, удалением импорта и ненужного view. - person José Pereda; 30.07.2016
comment
Я могу представить, это должно быть довольно сложно, но спасибо за огромную помощь! Библиотеки Gluon Mobile и javafxports были чрезвычайно полезны, и спасибо за отличную работу над ними! - person Aniket Joshi; 31.07.2016
comment
AVAudioSession *session = [AVAudioSession sharedInstance]; [session setCategory:AVAudioSessionCategoryPlayback error:&error]; [session setActive:YES error:nil]; Если вы поместите этот код в Audio.m до создания экземпляра объекта AVAudioPlayer, аудиофайл будет воспроизводиться, даже если была нажата кнопка аппаратного отключения звука на устройстве. - person Aniket Joshi; 04.08.2016
comment
src/ios/jniLibs/libCharm.a все еще действительный путь ... Если libLog.a создано ios-build.gradle из docs.gluonhq.com/samples/gonative разместить там (внутри GoNativeApp), чтобы System.loadLibrary("Log) мог найти его там? - person lelelo; 14.01.2018
comment
Пожалуйста, разместите новый вопрос. - person José Pereda; 14.01.2018