2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UnityからAR Foundation経由でAR Kitを利用したとき、Application.RequestUserAuthorizationが動かない

Posted at

仕事でARアプリケーションを作っていたのだが、 Application.RequestUserAuthorization が動作していない。
仕様上、画面をタッチしてアプリをスタート! みたいな画面で、権限の要求 & 拒否されたのであれば権限が必要な旨を通知したい。さて…。

原因は何か

Debug.Logを大量に貼り、どこまで処理が動いていて、どこまで処理が動いていないかを探っていく。
直前の権限確認と、分岐までは動いているので どうやら Application.HasUserAuthorization は動作しているようだ。 動いてなかった。Application.HasUserAuthorization に失敗したとき常に false を返すようになっているだけだったようだ。

ということは、C#スクリプトに問題があって私の書いた処理が動いていないわけではなく、なぜかわからないが Application.RequestUserAuthorization だけが限定的に処理をスキップされているようだ。

iOS用にコンバートされた処理を追っていく

ビルドされたxcodeprojファイルを開き、中を見る。
自動生成された難読なコードが大量に出てきてげんなりするが、Debug.Logを大量に貼っていたのが功を奏した。
XCodeで ababababab など、Application.RequestUserAuthorization を呼び出している部分の前後に置いた文字列で検索しつつ、なんとかコードを追っていくと、 UnityRequestAVCapturePermission という関数にたどり着いた。

#if !PLATFORM_TVOS && (UNITY_USES_WEBCAM || UNITY_USES_MICROPHONE)

たどりついたのは、 Classes > UnityにあるAVCapture.mmというふぁいるにあるUnityRequestAVCapturePermissionという関数だった。
関数名で察しはつくが、どうやらUnity上で呼ばれたApplication.RequestUserAuthorizationなどのObj-C側の実態っぽい。
中身はこんな感じだ

AVCapture.mm
#include "AVCapture.h"

#include <AVFoundation/AVFoundation.h>


static NSString* MediaTypeFromEnum(int captureType)
{
    if (captureType == avAudioCapture)
        return AVMediaTypeAudio;
    else if (captureType == avVideoCapture)
        return AVMediaTypeVideo;
    return nil;
}

extern "C" int UnityGetAVCapturePermission(int captureType)
{
    NSString* mediaType = MediaTypeFromEnum(captureType);
    if (mediaType == nil)
        return avCapturePermissionDenied;

#if !PLATFORM_TVOS && (UNITY_USES_WEBCAM || UNITY_USES_MICROPHONE)
    NSInteger status = AVAuthorizationStatusAuthorized;
    status = [AVCaptureDevice authorizationStatusForMediaType: mediaType];

    if (status == AVAuthorizationStatusNotDetermined)
        return avCapturePermissionUnknown;
    else if (status == AVAuthorizationStatusAuthorized)
        return avCapturePermissionGranted;
#endif

    return avCapturePermissionDenied;
}

extern "C" void UnityRequestAVCapturePermission(int captureType)
{
#if !PLATFORM_TVOS && (UNITY_USES_WEBCAM || UNITY_USES_MICROPHONE)
    NSString* mediaType = MediaTypeFromEnum(captureType);
    if (mediaType == nil)
        return;

    [AVCaptureDevice requestAccessForMediaType: mediaType completionHandler:^(BOOL granted) {
        UnityReportAVCapturePermission();
    }];
#endif
}

気になるのは #if !PLATFORM_TVOS && (UNITY_USES_WEBCAM || UNITY_USES_MICROPHONE) のあたり。というかこれしかない。絶対これだ。
調べてみると以下のようなスレッドがあった https://forum.unity.com/threads/ios-app-never-asks-for-microphone-permissions.450307/ 要約すると、

  • Application.RequestUserAuthorizationが上手く動いてない
  • どうやら UNITY_USES_MICROPHONE が定義されていないっぽい

ということのようだ。
上記のスレッドは2017年の物なのだが、なぜか同じような問題が再発しているようだ。

(噂によるとUnityからARKitを使うとこの辺をARKitが握ってしまうのでうまく動作しなくなるとの事だが、詳細は不明)

解決方法

解決方法は簡単、というかゴリラ並みの力技だが、以下のように修正するだけだ

AVCapture.mm
#include "AVCapture.h"

#include <AVFoundation/AVFoundation.h>


static NSString* MediaTypeFromEnum(int captureType)
{
    if (captureType == avAudioCapture)
        return AVMediaTypeAudio;
    else if (captureType == avVideoCapture)
        return AVMediaTypeVideo;
    return nil;
}

extern "C" int UnityGetAVCapturePermission(int captureType)
{
    NSString* mediaType = MediaTypeFromEnum(captureType);
    if (mediaType == nil)
        return avCapturePermissionDenied;

#if !PLATFORM_TVOS
    NSInteger status = AVAuthorizationStatusAuthorized;
    status = [AVCaptureDevice authorizationStatusForMediaType: mediaType];

    if (status == AVAuthorizationStatusNotDetermined)
        return avCapturePermissionUnknown;
    else if (status == AVAuthorizationStatusAuthorized)
        return avCapturePermissionGranted;
#endif

    return avCapturePermissionDenied;
}

extern "C" void UnityRequestAVCapturePermission(int captureType)
{
#if !PLATFORM_TVOS
    NSString* mediaType = MediaTypeFromEnum(captureType);
    if (mediaType == nil)
        return;

    [AVCaptureDevice requestAccessForMediaType: mediaType completionHandler:^(BOOL granted) {
        UnityReportAVCapturePermission();
    }];
#endif
}

何をしたかというと、 #if !PLATFORM_TVOS && (UNITY_USES_WEBCAM || UNITY_USES_MICROPHONE)#if !PLATFORM_TVOS と修正した。

UNITY_USES_MICROPHONE および UNITY_USES_WEBCAM はUnity側で Microphone Usage Description, Camera Usage Description を設定していないときの安全装置(設定してないと権限要求した時点でアプリが落ちる)らしいのだが、もちろんDescriptionは設定してあるので、とりあえずなくなっても大丈夫だろう。

場当たり的な対処しかできないのが歯がゆいが、差し当たって問題なくアプリは動いている。

気になるのはなんでこんなことになるのかという原因の部分だが、ここまで探るので結構疲れたのでそれはまた今度…。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?