5
5

More than 1 year has passed since last update.

iOSでSafari以外のブラウザを起動する

Last updated at Posted at 2021-10-24

動機

あるアプリの開発時にGoogle ChromeまたはMicrosft EdgeでURLを開くようにコーディングして欲しいと言われました。
iOSではWeb画面のレンダリングエンジンWKWebViewと決まっていて、他のレンダリングエンジンを使うと審査を通らないのですが、他の理由から特定のブラウザを使いたいということもあるのかもしれませんね。

Webブラウザアプリのスキームを調べてみた

ということでWebブラウザアプリのスキームを調べました。
条件としてhttp/httpsを明示的に切り分けられるように出来ていることです。
http/httpsを自分のスキームに書き換えるタイプと、URLをURLエンコードして自分のURLにパラメータとしてセットするタイプとに別れます。

アプリ HTTP HTTPS URLをパラメータとして
Google Chrome googlechrome:// googlechromes:// false
Mozilla Firefox firefox://open-url?url= firefox://open-url?url= true
Mozilla Firefox Focus firefox-focus://open-url?url= firefox-focus://open-url?url= true
Opera Touch touch-http:// touch-https:// false
Opera Mini opera-http:// opera-https:// false
Microsoft Edge microsoft-edge-http:// microsoft-edge-https:// false
Brave brave://open-url?url= brave://open-url?url= true
Kaspersky Browser kaspersky-safebrowser-http:// kaspersky-safebrowser-https:// false
Smooz smooz://url/ smooz://url/ true
Lunascape ilunascape:// ilunascapes:// false
Sleipnir shttp:// shttps:// false
Aloha Browser alohabrowser://open?link= alohabrowser://open?link= true
i-FILTER Browser ifilter:// ifilters:// false
CroPlus Webブラウザの安全性みどり chromtorhttp:// chromtorhttps:// false
MobileIron Web@Work mibrowser:// mibrowsers:// false
Ohajiki Webブラウザ oodhttp:// oodhttps:// false

以下のようなSwiftコードでウェブブラウザの一覧を作りました。

WebBrowser.swift
import SwiftUI

class WebBrowser : NSObject {

    fileprivate static let HTTP_SCHEME = "http://"
    fileprivate static let HTTPS_SCHEME = "https://"

    fileprivate var _title = ""
    internal var title: String {
        return _title
    }
    fileprivate var _httpScheme = HTTP_SCHEME
    internal var httpScheme: String {
        return _httpScheme
    }
    fileprivate var _httpsScheme = HTTPS_SCHEME
    internal var httpsScheme: String {
        return _httpsScheme
    }
    fileprivate var _urlAsParameter = false
    internal var urlAsParameter: Bool {
        return _urlAsParameter
    }

    /**
     constructor.
     */
    init(_ title: String, http: String, https: String, asParam: Bool) {
        super.init()
        _title = title
        _httpScheme = http
        _httpsScheme = https
        _urlAsParameter = asParam
    }

    /**
     get web browser URL.
     - parameter url: URL string.
     - returns: URL string for the web browser.
     */
    func webBroeswerURL(_ url: String) -> String {
        var urlString = ""
        if url.hasPrefix(WebBrowser.HTTPS_SCHEME) {
            urlString = webBroeswerURL(url, isSecure: true)
        }
        else if url.hasPrefix(WebBrowser.HTTP_SCHEME) {
            urlString = webBroeswerURL(url, isSecure: false)
        }

        print("title: \(title), urlString: \(urlString)")
        return urlString
    }

    /**
     get web browser URL.
     - parameter url: URL string.
     - parameter isSecure: true for https, false for http.
     - returns: URL string for the web browser.
     */
    private func webBroeswerURL(_ url: String, isSecure: Bool) -> String {
        var urlString = ""
        let myScheme = isSecure ? _httpsScheme : _httpScheme
        let prefix = isSecure ? WebBrowser.HTTPS_SCHEME : WebBrowser.HTTP_SCHEME

        if myScheme.hasPrefix(prefix) {
            urlString = url
        }
        else {
            if _urlAsParameter == false {
                let index = url.index(url.startIndex, offsetBy: prefix.count)
                urlString = myScheme + url[index...]
            }
            else {
                urlString =  myScheme + (url.addingPercentEncoding(withAllowedCharacters: .letters) ?? "")
            }
        }
        return urlString
    }

    /**
     add web browser definition into the web browser list.
     - parameter list: web browser list.
     */
    class func addWebBrowsers(_ list: inout [WebBrowser]) {
        list.append(WebBrowser("Default Browser", http: "http://", https: "https://", asParam: false))
        list.append(WebBrowser("Google Chrome", http: "googlechrome://", https: "googlechromes://", asParam: false))
        list.append(WebBrowser("Firefox", http: "firefox://open-url?url=", https: "firefox://open-url?url=", asParam: true))
        list.append(WebBrowser("Firefox Focus", http: "firefox-focus://open-url?url=", https: "firefox-focus://open-url?url=", asParam: true))
        list.append(WebBrowser("Opera Touch", http: "touch-http://", https: "touch-https://", asParam: false))
        list.append(WebBrowser("Opera Mini", http: "opera-http://", https: "opera-https://", asParam: false))
        list.append(WebBrowser("Microsoft Edge", http: "microsoft-edge-http://", https: "microsoft-edge-https://", asParam: false))
        list.append(WebBrowser("Brave", http: "brave://open-url?url=", https: "brave://open-url?url=", asParam: true))
        list.append(WebBrowser("Kaspersky Browser", http: "kaspersky-safebrowser-http://", https: "kaspersky-safebrowser-https://", asParam: false))
        list.append(WebBrowser("Smooz", http: "smooz://url/", https: "smooz://url/", asParam: true))
        list.append(WebBrowser("Lunascape", http: "ilunascape://", https: "ilunascapes://", asParam: false))
        list.append(WebBrowser("Sleipnir", http: "shttp://", https: "shttps://", asParam: false))
        list.append(WebBrowser("Aloha Browser", http: "alohabrowser://open?link=", https: "alohabrowser://open?link=", asParam: true))
        list.append(WebBrowser("i-FILTER Browser", http: "ifilter://", https: "ifilters://", asParam: false))
        list.append(WebBrowser("CroPlus", http: "chromtorhttp://", https: "chromtorhttps://", asParam: false))
        list.append(WebBrowser("MobileIron Web@Work", http: "mibrowser://", https: "mibrowsers://", asParam: false))
        list.append(WebBrowser("Ohajiki D Web Browser", http: "oodhttp://", https: "oodhttps://", asParam: false))
    }
}

上記WebBrowser.swiftをContentView.swiftからは以下のように利用しています。

ContentView.swift
import SwiftUI

struct ContentView: View {

    internal static let QIITA_URL = "https://qiita.com/"

    @State private var urlInput = ""
    @State private var showingOptions = false
    @State private var browser: String
    @State private var browserIndex = 0
    fileprivate var _webBrowsers = [WebBrowser]()

    init() {
        WebBrowser.addWebBrowsers(&_webBrowsers)
        browser = _webBrowsers[0].title
        print("init: done! browser: \(browser)")
    }

    var body: some View {
        VStack(alignment: .leading) {
            HStack(alignment: .center) {
                Spacer()
                Button(browser) {
                    showingOptions = true
                }.confirmationDialog("Select Browser",
                                     isPresented: $showingOptions,
                                     titleVisibility: .visible) {
                    ForEach(_webBrowsers.indices) { index in
                        let webBrowser = _webBrowsers[index]
                        let urlString = webBrowser.webBroeswerURL(ContentView.QIITA_URL)
                        if let url = URL(string: urlString) {
                            let enable = UIApplication.shared.canOpenURL(url)
                            if enable {
                                Button(webBrowser.title) {
                                    browser = webBrowser.title
                                    browserIndex = index
                                }
                            }
                        }
                    }
                }
                Spacer()
            }
            HStack(alignment: .center) {
                TextField("Input URL", text: $urlInput)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                    .keyboardType(.URL)
                    .disableAutocorrection(true)
                    .autocapitalization(.none)
                    .submitLabel(.go)
                    .onSubmit {
                        gotoURL()
                    }
                    .padding()
                Button("Go") {
                    gotoURL()
                }
            }
        }.padding()
    }

    func gotoURL() {
        let webBrowser = _webBrowsers[browserIndex]
        let urlString = webBrowser.webBroeswerURL(urlInput)
        if urlString.count > 0 {
            if let url = URL(string: urlString) {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

iOSアプリで非標準Webアプリスキームを呼びだせるようにするためにはInfo.plistに以下の記述でスキームを追加します。

Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>LSApplicationQueriesSchemes</key>
    <array>
        <string>googlechromes</string>
        <string>googlechrome</string>
        <string>firefox</string>
        <string>firefox-focus</string>
        <string>touch-https</string>
        <string>touch-http</string>
        <string>microsoft-edge-https</string>
        <string>microsoft-edge-http</string>
        <string>brave</string>
        <string>ilunascapes</string>
        <string>ilunascape</string>
        <string>shttps</string>
        <string>shttp</string>
        <string>alohabrowser</string>
        <string>smooz</string>
        <string>oodhttps</string>
        <string>oodhttp</string>
        <string>kaspersky-safebrowser-https</string>
        <string>kaspersky-safebrowser-http</string>
        <string>ifilters</string>
        <string>ifilter</string>
        <string>chromtorhttps</string>
        <string>chromtorhttp</string>
        <string>opera-https</string>
        <string>opera-http</string>
        <string>mibrowsers</string>
        <string>mibrowser</string>
    </array>
</dict>
</plist>

iOS15で一つ困ったこと

iOS15で一つ困ったことがありまして、iOS14ではデフォルトブラウザをSafariから変更すると UIApplication.shared.canOpenURL(_:) メソッドはhttpスキームの問い合わせにfalseを返してくれていたのですが、iOS15では常にtrueと返ってくるようになりました。Swiftコードからはデフォルトブラウザが変更されたかどうかがわからなくなりました。
Appleってこういうちゃぶ台返しを平気でやってくる会社ですね。
ただ、ユーザが指定したデフォルトブラウザの選択にベンダーが介入すべきではないのかもしれません。日本の業務アプリベンダーの考え方がAppleのそれとは相容れないのかもしれませんね。

動かしてみてください

iPhoneシミュレータでは、App Storeからアプリのインストールができないので、実機でテストするしかありません。
以下のGitHubのURLからアンプルプロジェクトをダウンロードして、Signing & CapabilitiesのBundle Identifierをご自分のものに書き換え、ご自分のProvisioning Profileをあてがってやってテストしてみてください。
t-kageyama/WebBrowserSelector: Sample project for select specific Web Browser on iOS.

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