「iPad」カテゴリーアーカイブ

【Xcode】各種ユーザーデータを初期処理する際の注意

【macOS Sierra 10.12.6+Xcode 8.3.3+iPhoneSE(iOS 10.3.2)】

とあるアプリで、カメラロールの写真とミュージックのアートワークを使ってたんですが、何故かインストール直後にどちらも0件になってしまう事象が発生。2回目以降に起動すると使えるのに・・・。

と思って調べたら、初期処理の実行タイミングに問題がありました。

※ここでいう「初期処理」とは、各種ライブラリをこのアプリ使うための実装処理を指します。

iOS10以降は各種ユーザーデータへアクセスに許可が必要になりました。で、以前書いたようにinfo.plistにメッセージ用テキストが必須になったわけですが、これで使用許可を求めるダイアログを表示してくれますが、該当処理はダイアログによる許可を待ってくれるわけではなく、許可されないと(ダイアログのボタンを押さないと)無視されてしまうようです。

で、viewDidLoad に書いてあった写真ライブラリとメディアライブラリの初期処理が、インストール直後でも正しく実行されるように、以下のように修正しました。

    //写真ライブラリ:初回許可(未設定の場合にダイアログの選択結果を受け取って、初期処理を行う)
    PHAuthorizationStatus status_photo = [PHPhotoLibrary authorizationStatus];
    if (status_photo == PHAuthorizationStatusNotDetermined){
        // このアプリに与える権限が未選択(アプリ初回起動時)
        NSLog(@"---PHPhotoLibrary:未選択");
        
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            if (status == PHAuthorizationStatusAuthorized) {
                // Access has been granted.
                NSLog(@"-----写真ライブラリ:使用OK");
                [self initIconList_photo];
            }
            else {
                // Access has been denied.
            }
        }];
        
    } else if (status_photo == PHAuthorizationStatusAuthorized){
        NSLog(@"-----写真ライブラリ:使用OK済み");
        [self initIconList_photo];
        
    }
    
    //メディアライブラリ設定:初回許可(未設定の場合にダイアログの選択結果を受け取って、初期処理を行う)
    MPMediaLibraryAuthorizationStatus status_media = [MPMediaLibrary authorizationStatus];
    if (status_media == MPMediaLibraryAuthorizationStatusNotDetermined){
        // このアプリに与える権限が未選択(アプリ初回起動時)
        NSLog(@"---MPMediaLibrary:未選択");
        
        [MPMediaLibrary requestAuthorization:^(MPMediaLibraryAuthorizationStatus status) {
            if (status == MPMediaLibraryAuthorizationStatusAuthorized) {
                // Access has been granted.
                NSLog(@"-----メディアライブラリ:使用OK");
                [self initIconList_artwork];
            }
            else {
                // Access has been denied.
            }
        }];
        
    } else if (status_media == MPMediaLibraryAuthorizationStatusAuthorized){
        NSLog(@"-----メディアライブラリ:使用OK済み");
        [self initIconList_artwork];
    }

要は、requestAuthorization でそれぞれのライブラリの使用許可ダイアログの結果を受け取って、OK(写真なら PHAuthorizationStatusAuthorized)だった場合に、初期処理(写真の場合は、initIconList_photo )を実行するということです。

ちなみに、else if で書かれているのは、既に許可済みの場合(写真だと PHAuthorizationStatusAuthorized)の場合に、初期処理を実行するためです(これがないと、後から許可した場合に初期処理が実行されない)。

各種ライブラリへのアクセス許可のダイアログは、info.plistにメッセージ用テキストを必須条件として、プログラム中で初めて該当ライブラリにアクセスしたタイミングで表示されるので、写真ライブラリとメディアライブラリのチェック順を入れ替えれば、ダイアログを出す順番も制御できます。また、特に初期処理が要らないライブラリなら、ユーザーがボタンを押したタイミングで許可を求めるダイアログを表示することもできそうです。

【参考】
iOSでカメラと写真の利用許可の確認方法[AVCaptureDevice] – Qiita
【Xcode】iOS10以降は各種ユーザーデータへアクセスに許可が必要 | AS blind side
【Xcode】iOS10で各種ユーザーデータへのアクセス許可を参照 | AS blind side
requestAuthorization: – MPMediaLibrary | Apple Developer Documentation

【Xcode】効果音と多重再生とSFSpeechRecognizer(音声認識)

作成中のアプリで使おうと思って調べたメモです。

サウンドの再生方法


調べてみると、下記の2つの方法があって、それぞれ用途によって総称されているフレームワークが違っている。

・AudioToolBoxを使う方法(効果音等短い音)
・AVFoundationを使う方法(BGM等長い音やループ)

【参考】
Objective-C:音楽(BGM)や効果音(SE)等のサウンド再生方法 | siro:chro
アプリ開発ブログ(仮): 効果音を鳴らす
【Xcode】アプリ内のボタンに効果音を付ける! | iDEACLOUD/dev

BGMと効果音を併用する際の問題点


効果音はAudioToolBox、BGMはAVFoundationで鳴らせばいいのかと思って、効果音をAudioToolBoxで組み込んで、テスト中にミュージックアプリで音楽流しながら、効果音を鳴らしたら音楽がフェードアウトしてしまった。で、調べてみたら、どうもAudioToolBoxとAVFoundationの併用に問題があるらしいことが発覚。

以下のリンクによれば、AudioToolBoxで音を鳴らすと、AVFoundationの方はフェードアウトしてしまうらしい。
なので、効果音もAVFoundationで再生することにする。

【参考】
BGMを鳴らしながら効果音再生するときの落とし穴 – iOSアプリ開発まとめWiki – アットウィキ

多重再生するための設定


更に調べてみると、多重再生させるには、以下の2つが必要とのこと。

・音声ファイルを .caf形式にする
・AVAudioSessionのカテゴリを変更する

.cafとは、Core Audio File の拡張子で、iOSおよびOS Xのネイティブのオーディオファイルフォーマットらしいです。

ターミナルから以下のコマンドで変換できます(例:sound_ok.m4a を sound_ok.caf に変換)

afconvert -f caff -d 0 sound_ok.m4a sound_ok.caf

※変換したところ、ファイルサイズは【107KB】>>【54KB】になりました。

また、AVAudioSessionのカテゴリは、デフォルトではオーディオ再生中にアプリを起動するとオーディオが停止(AVAudioSessionCategorySoloAmbient)するようになっているので、どちらも鳴らせるように設定を変更します。Objective-Cだと、AppDelegate.m にこんな感じに書きます。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // バックグラウンドでの音の再生を許可
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
    return YES;
}

【参考】
Swift:AVAudioSession アプリのバックグラウンドで音楽を再生する | siro:chro
iPhoneアプリ開発のためのサウンドフォーマットまとめ | ぱーくん plus idea
Core Audioの概要【PDF】
【iOS】音楽を止めずに効果音を同時に再生するには|てくめも@ecoop.net

SFSpeechRecognizer(音声認識)で効果音が再生されない問題


SFSpeechRecognizer(音声認識)を使ったアプリに効果音を組み込んでみたら、SFSpeechRecognizerを使って音声認識した後に、効果音が鳴らなくなった。

結果的には、SFSpeechRecognizerを使って音声認識を実行した後に、もう一度AVAudioSessionのカテゴリを変更してやることで解決しました。Objective-Cだと、こんな感じ。

// バックグラウンドでの音の再生を許可(AppDelegateで設定しているが、speechRecognizer使用後に再度設定しないと、音が鳴らない)
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];

SFSpeechRecognizer自体はここでは触れないので、下記リンクを参照して下さい。要は、SFSpeechRecognizerを使う際にAVAudioSessionのカテゴリを録音用に変更(AVAudioSessionCategoryRecord)しているので、それを戻さないと音が鳴らないということです。

【参考】
[iOS 10] SFSpeechRecognizerで音声認識を試してみた | Developers.IO