post Image
特定のアプリがインストール済みかチェックする

iOS で特定のアプリがインストールされているかチェックする方法と、それに関する疑問点の調査結果を書いていきます。

インストール済みかチェック手順

Info.plist に Scheme を登録して、 canOpenURL メソッドを実行するだけです。

例えば、 Twitter アプリがインストール済みかチェックするには下記の手順を行います。

1. Info.plist に Scheme 登録

スクリーンショット 2017-07-12 17.08.04.png

LSApplicationQueriesSchemes というキーで、 Type は Array にして、 twitter を登録します。

2. canOpenURL を実行

Twitter のアプリがインストールをした状態で、 canOpenURL を実行してみます。

if UIApplication.shared.canOpenURL(URL(string: "twitter://")!) {
    print("Twitter インストール済み")
 } else {
    print("Twitter インストールされていない")
}

実行結果に Twitter インストール済み が表示されました。
これで Twitter アプリがインストール済みか特定することができました。

参考: canOpenURL(_:) – UIApplication | Apple Developer Documentation

疑問点

Info.plist に書かずに canOpenURL を実行したら?

false が返却されるだけで、 warning log やクラッシュはありませんでした。

Info.plist に書かずに特定のアプリを開こうとしたら?

アプリの Open はできるようです、下記のダイアログが表示されアプリを開くことができました。

asset_PNG__750×1334_.png

LSApplicationQueriesSchemes はアプリの存在確認に必要なだけで、開く場合はチェックなどは不要なようです。しかし、インストールされていないのにそのアプリを開こうとしても何も起きないので、チェックした上で開かないとユーザ体験がよくないですね。

let url = URL(string: "twitter://")!
if #available(iOS 10.0, *) {
    UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
    UIApplication.shared.openURL(url)
}

iOS 10 以降でアプリを起動するメソッドが変わったようですね。
参考: [iOS 10] UIApplication の openURL: が Deprecated になりました | Developers.IO

このパターンはコメントで指摘いただきました、 @ktysne さんありがとうございます!

存在しない Scheme のアプリを開こうとしたら?

存在しない false というアプリを開こうとしてみましたが、ログも何も出ず、何も起きませんでした。

let url = URL(string: "false://")!
if #available(iOS 10.0, *) {
    UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
    UIApplication.shared.openURL(url)
}

Scheme が重複したらどうなる?

本家 Twitter アプリとは別に、 twitter という scheme を持った別のサンプルアプリを作って実行してみたところ、 サンプルアプリが起動しました
(後にインストールしたアプリが勝つ?)

セキュアな情報を渡していると、 scheme を重複させられて情報を引っこ抜かれる可能性がありますので注意が必要です。 canOpenURLtrue だとしても自分の望むアプリかは不明なので、全幅の信頼を置くのはやめましょう。

アプリのアップデートが必須か?

Info.plist を変えるにははアプリのアップデートが必要で、つまり Apple の審査を通さねばなりません。
サーバから scheme をもらって動的に canOpenURL の引数を変更はできません。

iOS8 までは canOpenURL で他のアプリを調べ放題だったのですが、プライバシーへの配慮で iOS9 以降はこの仕様になったようです。
参考: iOS9でカスタムURLスキームの遷移に失敗するときの注意点 – Qiita

Universal Links でインストール済みか取れないか?

多分ダメ。(多分なのは実際には試していないので…)

Universal Links に対応するにはサーバ + アプリの両方で対応が必要であり、他所のアプリが Universal Links を利用してインストール済みかを取得できません。
また、URL を Safari で開こうすると Universal Links 対応かが自動で判定され、そのアプリが自動で立ち上がります。そのため、自アプリから他所のアプリがインストールされているかの確認はできません。

Universal Links は安全性や非公開性などの思想で設計されているため、これを Hack してインストール状況などは取得不可です。

参考アプリ

Launcher – 通知センターウィジェット搭載ランチャー

アプリを開くだけならば Info.plist に書いておく必要はないため、一般的な Scheme をアプリ内に保持して、マイナーなアプリはカスタム Scheme としてユーザが手動で登録できそうです。

おわり

特定のアプリがインストール済みか調べたい場合、 Info.plist に scheme を登録して canOpenURL メソッドを叩く以外にインストール状況の取得はできなさそうです。

あまり変なことをやろうとせずに、素直に Apple 様に従いましょう。


『 Swift 』Article List