質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.10%

iOSでバックグラウンドから再生中の曲情報を取得する

解決済

回答 2

投稿

  • 評価
  • クリップ 2
  • VIEW 2,313

sont

score 30

iOSで、自分のアプリがバックグラウンドにいても、他のミュージック再生アプリで再生している曲情報を収集できるようにしたいと思っています。

http://marunouchi-tech.i-studio.co.jp/2569/
こちらのサイトの情報によると、Apple標準ミュージック再生アプリの情報であれば取得できるようなのですが、
自分のアプリがバックグラウンドにいるときでも監視してログとして、取得することはできるでしょうか?

どなたかアドバイスお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+1

iOSは許可された特定の状態のアプリ以外はプロセスが完全に停止します。
Appleが規定する動作(アプリがオーディオを再生しているとかGPSを取得している等)以外でバックグラウンドで動くことはできないのでそういったログ行為はできないと思います。

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    _player = [MPMusicPlayerController systemMusicPlayer];

    [_player beginGeneratingPlaybackNotifications];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(onPlayItemChanged:)
                                                 name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
                                               object:nil];

    [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

    return YES;
}


- (void)onPlayItemChanged:(NSNotification*)notify
{
    MPMediaPropertyPredicate*    pred;
    NSNumber*    persistentId = notify.userInfo[@"MPMusicPlayerControllerNowPlayingItemPersistentIDKey"];

    pred = [MPMediaPropertyPredicate predicateWithValue:persistentId
                                            forProperty:MPMediaItemPropertyPersistentID];

    MPMediaQuery*    query;

    query = [[MPMediaQuery alloc] initWithFilterPredicates:[NSSet setWithObject:pred]];

    for(MPMediaItem* item in query.items){
        NSLog(@"%s '%@' '%@' '%@' %@", __func__, item.title, item.artist, item.albumTitle, item.lastPlayedDate);
    }
}

- (void)application:(UIApplication *)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSLog(@"%s", __func__);
    completionHandler(UIBackgroundFetchResultNewData);
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/20 00:34

    fuzzballさんのと何も代わり映えしませんが手元のiOS9(iPhone6)でも同じように動いてました(Swiftあんま慣れてないのでObjective-Cで、、、)
    20〜30分音楽再生しながらバックグランドで放置しておいたら呼ばれてましたよ。

    Background FetchのcompletionHandlerを呼ぶまではメインスレッドのイベントループが普通に動くんでしょうね。そのためにNotifycationCenterのキューも処理されてしまうんだと思われます。completionHandlerはすぐに呼ぶよりも少しディレイ挟んでイベントループを回してやったほうがいいのかもしれません。

    Appleが意図してるかどうかはわかりませんがこの動作は他にも使い道があるような気がしますね。

    >> また、私が知っている「とある」アプリは、

    僕も身近なアプリで知ってます。裏で無音のオーディオ回してるやつ。
    適当に理由つけるかこっそりの部分以外に明らかに普通に必要な部分があったら通るんですよね、、、

    キャンセル

  • 2016/10/20 11:01

    なるほど。ありがとうございます!
    私の方でももう少し詳しくチェックしてみて動作確認してみます。
    もし分からなかったらソース貼り付けたいと思います。

    ちなみに、toki_tdさんでの環境は実機をPC接続して、ログを監視していましたか?

    キャンセル

  • 2016/10/21 00:55

    そうです。iPhone6でデバッグ実行しながら音楽を再生してホーム画面でほったらかしてました。
    定期的にXcode上にログが出るのを確認してます。

    キャンセル

checkベストアンサー

0

出来るか出来ないかという話でしたら、出来ます。というか出来ました。
CoreLocationを使ってバックグラウンド処理を行い、1時間ほど放置した結果です。

2016-10-18 09:32:25.378 test[3519:239320] not playing
2016-10-18 09:32:35.719 test[3519:239449] Title : California (There Is No End to Love)
:
2016-10-18 10:20:35.243 test[3519:249911] Title : This Is Where You Can Reach Me Now
2016-10-18 10:20:45.252 test[3519:249910] not playing
:
2016-10-18 10:48:45.250 test[3519:254771] not playing

 BackgroundFetch + Notification

うっかりObjective-Cで書いてしまいました。

- (void)initNotif
{
    MPMusicPlayerController *player = [MPMusicPlayerController systemMusicPlayer];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(nowPlayingItemDidChange:)
                                                 name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
                                               object:player];
    [player beginGeneratingPlaybackNotifications];
}

- (void)nowPlayingItemDidChange:(NSNotification *)notif
{
    MPMediaEntityPersistentID persistentID = [notif.userInfo[@"MPMusicPlayerControllerNowPlayingItemPersistentIDKey"] unsignedLongLongValue];
    NSLog(@"persistentID=%llu", persistentID);

    MPMediaQuery *query = [MPMediaQuery new];
    MPMediaPropertyPredicate *pred = [MPMediaPropertyPredicate predicateWithValue:@(persistentID)
                                                                      forProperty:MPMediaItemPropertyPersistentID
                                                                   comparisonType:MPMediaPredicateComparisonEqualTo];
    [query addFilterPredicate:pred];
    NSArray<MPMediaItem *> *items = [query items];
    //NSLog(@"items=%@", items);

    [items enumerateObjectsUsingBlock:^(MPMediaItem *item, NSUInteger idx, BOOL *stop) {
        MPMediaType mediaType = [[item valueForProperty:MPMediaItemPropertyMediaType] unsignedIntegerValue];
        if (mediaType == MPMediaTypeMusic)
        {
            NSLog(@"%@ [%@] [%@] [%@] %f", item.lastPlayedDate, item.title, item.albumTitle, item.artist, item.playbackDuration);
        }
    }];
}

performFetchWithCompletionHandlerの中ではNSLogを空撃ちしているだけです。
これでしばらく放置してみました。

2016-10-19 19:48:46 test[8916] persistentID=1294602247482248857
2016-10-19 19:48:46 test[8916] 2016-10-19 10:30:22 +0000 [The Miracle (Of Joey Ramone)] [Songs of Innocence] [U2] 255.382000

2016-10-19 20:00:39 test[8916] persistentID=1294602247482248854
2016-10-19 20:00:39 test[8916] 2016-10-19 10:54:55 +0000 [Every Breaking Wave] [Songs of Innocence] [U2] 252.162000
2016-10-19 20:00:39 test[8916] [fetch]
2016-10-19 20:00:39 test[8916] persistentID=1294602247482248852
2016-10-19 20:00:39 test[8916] 2016-10-19 10:58:55 +0000 [California (There Is No End to Love)] [Songs of Innocence] [U2] 239.846000

2016-10-19 20:23:17 test[8916] persistentID=1294602247482248855
2016-10-19 20:23:17 test[8916] 2016-10-19 11:02:41 +0000 [Song for Someone] [Songs of Innocence] [U2] 226.763000
2016-10-19 20:23:17 test[8916] [fetch]
2016-10-19 20:23:17 test[8916] persistentID=1294602247482248860
2016-10-19 20:23:17 test[8916] 2016-10-19 11:08:01 +0000 [Iris (Hold Me Close)] [Songs of Innocence] [U2] 319.457000

2016-10-19 20:32:18 test[8916] persistentID=1294602247482248862
2016-10-19 20:32:18 test[8916] 2016-10-19 11:29:52 +0000 [This Is Where You Can Reach Me Now] [Songs of Innocence] [U2] 305.134000
2016-10-19 20:32:18 test[8916] [fetch]
2016-10-19 20:32:18 test[8916] persistentID=1294602247482248861
2016-10-19 20:32:18 test[8916] 2016-10-18 01:15:35 +0000 [The Troubles] [Songs of Innocence] [U2] 285.843000

うまくいってる?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/19 20:59

    おー!ありがとうございます!
    似たようなことをSwiftで再現しようとしてみました。
    アプリ起動後、標準のミュージックアプリで適当な曲を数曲再生し(最初から最後まで再生しました)、
    Xcodeから、Debug -> Simulate Background Fetchを実行しました。

    performFetchWithCompletionHandlerは呼ばれていたのですが、NotificationCenterは呼ばれていなかったっぽいです。

    fuzzballさんと何が違うんですかね。。。
    fuzzballさんのログを見る限り、persistentID=xxxが出力されるのは、曲が変わったタイミングではなく、Background fetchが呼ばれたタイミングでしょうか?

    Background fetchが呼ばれるタイミングで、今まで溜まっていたNotificationCenterのコールバックが呼ばれているという感じですか?

    キャンセル

  • 2016/10/19 21:15 編集

    >>Background fetchが呼ばれるタイミングで

    そうですね。ログのタイムスタンプを見ての通りです。ちなみに、Xcode7+iOS8+iPhone5です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる