🧊

モバイルブラウザからアプリを開くには

あいも変わらずモバイル情報です。

成果物はこちら。

leader22/app-opener

事の発端

よく見ますよね、モバイルサイトの至る所にある「Twitterでシェア」、「Facebookでシェア」ってボタン。
よく見るんですけど・・・押しますか?アレ。

TwitterFacebookも、もちろんアプリを使ってますよね。
ブラウザでなんて、誰もログインしてないですよね。

てことは誰も押さないですよね?!!

ネイティブアプリ全盛期にブラウザWebでシェアしてね!ったって、
わざわざログインしてまでやってくれる人が、果たしてどれくらいいるでしょうか。

うー、Webつらい!アプリ強い!
せめてこのボタンを押すとアプリが起動し・・たら素敵ではありませんか?!

どうにかなるのか

別に目新しい技術ではないのですが、実は"URIScheme"っていうものがあります。

URLスキーマって言われたりスキームって言われたり、色々呼ばれてます。
Androidだとインテントって呼んでたりもするらしい。

"http://" だとブラウザが起動するのと同じように、特定のアプリを呼び出すやつです。
Twitterなら"twitter://"とかです。
これらはアプリ側で定義されてある必要があります。

それならそうと

<a href="twitter://timeline">TwitterAppのタイムラインを表示!</a>

ってすりゃいいわけです。
楽勝です。

と言いたいところですが・・・。

  • アプリがインストールされてなかったら?
  • Androidでも動くのか?

とか気になってきますよね?
確かに動くし良いっちゃ良いのですが、そこは気にしないといけません。

app-opner.js

てなわけで作りました。

leader22/app-opener

iOS5以上、Android4以上で動くと思います。
厳密に色んな端末で検証したわけではないですが、手元のいくつかの端末では動いてました。

var isAndroid = navigator.userAgent.toLowerCase().indexOf('android') !== -1;
var shareText = encodeURIComponent('Webからアプリが開いたよ!! @leader22++ https://github.com/leader22/app-opener') + ' ';
var schemeStr = (isAndroid) ? 'intent://post?message=' + shareText + '#Intent;scheme=twitter;package=com.twitter.android;end;'
                            : 'twitter://post?message=' + shareText;
new AppOpener({
    schemeStr:   schemeStr,
    fallbackUrl: 'http://lealog.net'
});

って定義されたページでも用意しておけば、リンク踏むだけでおっけーです。
schemeStrさえ用意すれば、後はなんとかしてくれるライブラリです。

OS別の挙動について

iOS

有効なスキームだった場合は、思った通り動作します。
iOS Chromeでも、アプリ内WebViewでも問題なかったです。

ログインしてない場合などは、アプリは開きますがもちろんログイン画面に行きます。

普通のaタグだったりで直接コレを開こうとすると、
アプリがインストールされてない場合などに、無効なリンクとして処理されるっぽく、処理できない旨のalertが表示されます。

この味気ないalertではなく、それなりにハンドリングしたい・・ってあなた!
iframeを使えばなんとかなります!

冒頭のリポジトリからコードを見てみてくださいまし。

IPhone URL Schemes - akosma wiki

URIスキーム自体を探すのにはココが便利です。

Android

またもこいつに手を焼かれるのかとおもいきや、割とすんなりです。
ただAndroidのプロセス管理?の挙動がちょっとiOS民からすると特殊で、そこだけ注意します。

Androidの場合はインテントなる仕組みを使って実現します。
iOSと同じスキームでも動くっぽいのですが、どのアプリを使うかをユーザーに判断させるようなフローになるっぽい。
URL開く時に、「ブラウザで開く?それともChromeで開く?」って出るアレ。

アレもまぁある種親切なのですが・・・、
これを回避したい場合には、このインテントを使ってアプリを直接指定する他ないようです。

たとえばTwitterなら、

iOS: 'twitter://post?message={{TEXT}}'
ANDROID: 'intent://post?message={{TEXT}}#Intent;scheme=twitter;package=com.twitter.android;end;'

って感じです。

棚ぼた的な感じですが、この指定の仕方をしていると、該当するアプリがインストールされていない場合、
GooglePlayを開いてくれるという謎のフォールバック機能が!

どうやらAndroid Chromeではiframeから呼べないっぽいので、どちらでも動く愚直に開く方式にしました。

あ、一つ言い忘れました。
S Browser、お前だけは許さねぇ!

おや… S Browser 三銃士 の様子が…

いんたーねっと情報

Smallest piece of code that's going to change the... - Aawaara

こういう感じ?

これで晴れてアプリでシェアできる

できます。が。

実はいちばんやりたかったFacebookアプリの起動がどうにもこうにもできませんで・・。
正確には、起動まではいけるが、「1タップで即シェアな状態」までもっていくスキームが見つけられず・・。
Google先生に聞いてありとあらゆるパターンを試しましたがダメでした。

せっかく作ったのに勿体無いなーと思いつつ、
TwitterやLINE、その他のアプリはスキームさえあればコレで動くので、成果としてはまあ満足してはいるんですけどねー。

Facebookでシェアするスキーム!WANTED!

ほんとは

iOSAndroidのschemeStrの差まで吸収して、各SNSにシェアするメソッドまで定義しようと思ってました。
ただ、Facebookさまが使えないとなるともはや・・なので、自由に渡すカタチにしました。

iOSの場合のインストールされてなかったフックくらいは提供しても良かったのですが、特に使い道がないのでそっとしておきました。

ちなみに

Facebookさま曰く、

Don't prefill captions, comments, messages, or the user message parameter of posts with content a person didn’t create, even if the person can edit or remove the content before sharing.

つまり、できたところでポリシー違反にはなるので、それはそれでアレなんですが・・。

Platform Policy

やっぱりWebはWebらしく謙虚にいきましょうと思った春のひとときでした。