LoginSignup
13
5

More than 3 years have passed since last update.

Unity iOS/Androidで位置情報を取得する

Last updated at Posted at 2019-10-09

Unity上のiOS/Androidで位置情報を取得とiOS/Androidのパーミッションまわりについて試して見たことを記載します。

Unity公式の位置情報取得のサンプルコード

Unity公式の位置情報取得のサンプルコードのコメントを訳したものを下記に記載します。

このコードでも位置情報を取得できますが、Unityの位置情報の取得を管理するクラスLocationServiceがシンプルすぎて、iOS/Androidの位置情報取得の可否の状態によってどういう挙動をするのかがドキュメントからは不明瞭なので、本記事ではそのあたりを実機を動かして確認していきます。

using UnityEngine;
using System.Collections;

public class TestLocationService : MonoBehaviour
{
    IEnumerator Start()
    {
        // 最初に、ユーザーがロケーションサービスを有効にしているかを確認する。無効の場合は終了する
        if (!Input.location.isEnabledByUser)
            yield break;

        // 位置を取得する前にロケーションサービスを開始する
        Input.location.Start();

        // 初期化が終了するまで待つ
        int maxWait = 20; // タイムアウトは20秒
        while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
        {
            yield return new WaitForSeconds(1); // 1秒待つ
            maxWait--;
        }

        // サービスの開始がタイムアウトしたら(20秒以内に起動しなかったら)、終了
        if (maxWait < 1)
        {
            print("Timed out");
            yield break;
        }

        // サービスの開始に失敗したら終了
        if (Input.location.status == LocationServiceStatus.Failed)
        {
            print("Unable to determine device location");
            yield break;
        }
        else
        {
            // アクセスの許可と位置情報の取得に成功
            print("Location: " + Input.location.lastData.latitude + " "
                               + Input.location.lastData.longitude + " "
                               + Input.location.lastData.altitude + " "
                               + Input.location.lastData.horizontalAccuracy + " "
                               + Input.location.lastData.timestamp);
        }

        // 位置の更新を継続的に取得する必要がない場合はサービスを停止する
        Input.location.Stop();
    }
}

動作環境

  • Unity 2018.4f8 Mac版
  • XCode 11.0

各OSの位置情報取得の許可の状態について

iOSとAndroidのOSごとの位置情報取得の許可の状態について下記で記載します。
UnityではこのあたりがLocationServiceによって抽象化されてしまっています。

iOS

CLAuthorizationStatusに記載されているように、下記の5状態が存在します。

  • notDetermined - ユーザーは未選択
  • restricted - 許可されていない(ユーザーは特に拒否していないが何らかの理由で使用できない場合)
  • denied - ユーザーは拒否
  • authorizedAlways - 常に許可
  • authorizedWhenInUse - アプリの使用中のみ許可

notDetermined

ユーザーはアプリで位置情報サービスを使用できるかどうかを選択していない。

位置情報取得の確認ダイアログをまだ表示したことがないのがこの状態。

iOS 13.2.1での位置情報取得の確認ダイアログ
位置情報取得の確認ダイアログ

restricted

アプリは位置情報サービスの使用を許可されていない。

ユーザーは位置情報サービスの使用を特に拒否していないが、何らかの理由で使用できない場合にこの状態になるはず。
「設定 > プライバシー > 位置情報サービス」で位置情報サービスをオフにした場合はこの状態(iOS 13.1.2で確認)。

denied

ユーザーがアプリの位置情報サービスの使用を拒否したか、設定でグローバルに無効化されている。

位置情報の取得確認ダイアログで拒否を選択したか、「設定 > プライバシー > 位置情報サービス」で「なし」を選択したかのどちらかがこの状態。

authorizedAlways

ユーザーは、いつでも位置情報サービスを開始することをアプリに許可した。

位置情報の取得確認ダイアログで「常に」を選択するとこの状態になる。アプリがバックグラウンドにいてもアプリは位置情報が取得可能。

authorizedWhenInUse

ユーザーは、アプリが使用中に位置情報サービスを開始することを承認した。

位置情報の取得確認ダイアログで「使用中のみ」を選択するとこの状態になる。アプリがフォアグラウンドの状態でのみアプリは位置情報が取得可能。

Android

下記の3状態が存在する。

  • 未選択・1度だけ拒否
  • 許可済み
  • 拒否

未選択・1度だけ拒否

ユーザーはアプリで位置情報を使用できるかどうかを選択していない。
または、アプリで位置情報を使用を許可していない。

位置情報取得の確認ダイアログをまだ表示したことがないのがこの状態。
または、位置情報取得の確認ダイアログで拒否を選択したのがこの状態。

Android 9での位置情報取得の確認ダイアログ
位置情報取得の確認ダイアログ

許可済み

ユーザーは位置情報サービス使用することをアプリに許可した。

位置情報取得の確認ダイアログで許可を選択したのがこの状態。

拒否

アプリで位置情報を使用を許可していない。

位置情報取得の確認ダイアログで「今後表示しない」を選択したのがこの状態。

Android 9での位置情報取得の確認ダイアログで「今後表示しない」のチェックが存在するもの
位置情報取得の確認ダイアログで「今後表示しない」のチェックが存在するもの

位置情報取得の許可ごとの挙動について

LocationService.isEnabledByUser

LocationService.isEnabledByUser
ユーザーが位置情報サービスを有効にするかどうか。

iOS

「設定 > プライバシー > 位置情報サービス」で位置情報サービスをオフにした場合にfalseが返る。
位置情報の許可の有無とは関係なさそう。

状態 LocationService.isEnabledByUserの返値
notDetermined true
restricted false
denied true
authorizedAlways true
authorizedWhenInUse true

Android

状態 LocationService.isEnabledByUserの返値
未選択・1度だけ拒否 false
許可済み true
拒否 false

LocationService.Start

LocationService.Start
位置情報サービスの更新を開始します。
LocationService.Startを呼び出し後、LocationService.statusLocationServiceStatus.Runningになったら、LocationService.lastDataより位置情報を取得できます。

iOS

状態 LocationService.Start呼び出し後の動作
notDetermined 位置情報の取得の確認ダイアログが表示される。
restricted "位置情報を利用できるようにするには、位置情報をサービスをオンにしてください"というダイアログが表示される。LocationService.statusはFailedになる。
denied LocationService.statusはFailedになる。
authorizedAlways LocationService.statusはRunningになる。
authorizedWhenInUse LocationService.statusはRunningになる。

位置情報の取得の確認ダイアログで許可を選択した場合に、LocationService.statusRunningとなる。

"位置情報を利用できるようにするには、位置情報をサービスをオンにしてください"のダイアログ
"位置情報を利用できるようにするには、位置情報をサービスをオンにしてください"のダイアログ

Android

状態 LocationService.Start呼び出し後の動作
未選択・1度だけ拒否 位置情報の取得の確認ダイアログが表示される。LocationService.statusはStoppedのままで、許可を選択するとLocationService.isEnabledByUserはtrueになる。
許可済み LocationService.statusはRunningになる。
拒否 LocationService.statusはStoppedになる。

位置情報の取得の確認ダイアログで許可を選択しても、LocationService.isEnabledByUserはtrueになるがLocationService.statusの状態に変化はない。
位置情報を取得する場合はもう一度LocationService.Startを呼ぶ必要がありそう。

LocationService.Stop

LocationService.Stop
位置情報サービスの更新を停止します。

iOS/Android

LocationService.statusStoppedになります。
LocationService.lastDataの値が更新されなくなります。

まとめ

  • iOSは「設定 > プライバシー > 位置情報サービス」がオンかオフかはLocationService.isEnabledByUserを見れば分かる
  • iOSはアプリの位置情報取得が許可されているかどうかはあらかじめ分からない。LocationService.Startを呼んだ挙動で判定するしかなさそう。
  • iOSアプリは位置情報取得の許可ダイアログが表示されるかどうかはあらかじめ分からない。LocationService.Startを呼んだときにOSにより位置情報取得の許可ダイアログが表示される。

  • Androidはアプリの位置情報取得が許可されているかどうかはLocationService.isEnabledByUserを見れば分かる

  • Androidアプリは位置情報取得の許可が無い場合(LocationService.isEnabledByUserがfalseの場合)に、位置情報取得の許可ダイアログが表示されるかどうかはあらかじめ分からない。LocationService.Startを呼んだときにOSにより位置情報取得の許可ダイアログが表示される。

位置情報が取得できるかどうかをiOSとAndroidの両方に対応しようとすると、LocationService.Startを呼んだ上でLocationService.statusの値がどうなるかを監視するくらししかなさそうです。

コード

参考

13
5
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
13
5