Androidアプリ→ブラウザ起動→WEBサイトでログイン処理→URLスキームでアプリを再起動、そして指定したActivityに戻ってくる方法

　Androidアプリからブラウザを起動してWEBサイトに飛んで、ログイン処理などをした後、またアプリに戻ってくる方法のメモです。アプリ側はいろんなactivityからブラウザを起動できて、最後に元のactivityに戻ってくることを想定します。

#AndroidManifest.xmlの設定
```AndroidManifest.xml
<activity android:name=".MainActivity" android:launchMode="singleTask">
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="myappmain" android:host="callback" android:path="/param" />
  </intent-filter>
</activity>
<activity android:name=".SubActivity" android:launchMode="singleTask">
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="myappsub" android:host="callback" android:path="/param" />
  </intent-filter>
</activity>
```
+ activityが複数、MainActivityとSubActivityがあると仮定します。
+ `intent-filter`に`android.intent.category.BROWSABLE`を入れてアプリをブラウザから起動できるようにします。

+ activity毎に違うscheme名を付けておきます。

+ 最初にブラウザを開いたactivityに戻ってきたいので、`android:launchMode="singleTask"`を入れます。これを入れないと同名のactivityが二重に開いてしまいます。singleTaskの設定を入れた場合はactivityにonNewIntentを入れます（後述）。

#MainActivityでブラウザを起動
```MainActivity.java
//ランダム文字列（code）を作成して保存
CodeGenerator codeGenerator = new codeGenerator();
String code = codeGenerator.getRandomCode();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("CODE",code);
editor.apply();//またはeditor.commit()

//ブラウザ起動 codeとschemeをパラメータに入れておく
Uri uri = Uri.parse("https://hoge.jp/login/?code=" + code + "&scheme=myappmain");
Intent intent = new Intent(Intent.ACTION_VIEW,uri);
startActivity(intent);
```
+ 上で作成しているcodeはワンタイムパスワードの役割です。ブラウザを起動する度に毎回ランダム文字列を作成してcodeに入れて渡します。このcodeはSharedPreferenceなどアプリ内にも保存しておきます。
+ scheme名は、MainActivityからブラウザを起動して、またここに戻ってきたいので、AndroidManifestに設定したmyappmainを入れます。

#WEBサイト側の設定
+ /login/index.phpでcodeとschemeを受け取ります。idとパスワードを入れてログイン処理などをします（詳細は省略）。成功したらcomplete.phpに遷移してURLスキームでアプリに戻ってきます。complete.phpにはcodeとschemeを引き続き渡します。

```complete.php
<?php
//前のページからもらう
$code = $_POST["code"];
$scheme = $_POST["scheme"];
?>

//<head>部分
<script type="text/javascript">
window.onload = function(){
    //標準ブラウザ用URLスキーム
    location.href="<?=$scheme?>://callback/param?code=<?=$code?>"

    /*
    必要ならこの辺にiPhone用、Chromeブラウザ用にURLスキームを用意する
    */

}
</script>

//<body>部分
//location.hrefが効かなかった時のために、ボタンを残しておく
<form method="get" action="<?=$scheme?>://callback/param?code=<?=$code?>">
  <input type="submit" value="自動的にログインしない場合はこちら" />
</form>
```
+ scheme名で戻りたいactivityを指定できます。他のアプリとscheme名が重ならないような名前にする必要があります。
+ Chromeブラウザ用のURLスキームを用意するなら、location.hrefを`
 "intent://callback/param?code=<?=$code?>#Intent;scheme=<?=$scheme?>;package=パッケージ名;end";`にします。
+ `location.href`でURLスキームを指定して、アプリを再起動します。`location.href`効かない場合のためにbody内にボタンを残しておきます（ボタンを残さないで、ページを強制的に閉じても問題ないかもしれない）。

#MainActivityに戻ってくる
```MainActivity.java
//アプリに戻ってきた時にonResumeが呼ばれるので、そこでcodeなどを取得します
@Override
public void onResume(){
    super.onResume();

    Intent intent = getIntent();
    String action = intent.getAction();

    if (Intent.ACTION_VIEW.equals(action)) {
        Uri uri = intent.getData();
        if (uri != null) {
                
            String param1 = uri.getQueryParameter("code");

            String code = sharedPreferences.getString("CODE","ERROR");

            //さっき送り出したcodeと合っていれば任意の処理を入れます
            if(param1.equals(code)){
                    
                /*
                アプリ側の任意の処理
                アクセストークンなどを保存するとか
                */

            }
        }
    }
}

//AndroidManifestのactivityのlaunchModeをsingleTaskにした場合は、onNewIntentを入れてgetIntent()できるようにします
@Override
public void onNewIntent(Intent intent){
    super.onNewIntent(intent);
    setIntent(intent);
}
```
+ アプリに戻ってくると、onResumeが動きます。ここでgetIntent()でcodeなどを受けます。AndroidManifestに`android:launchMode="singleTask"`を設定している場合は`onNewIntent`を書き加えておきます。これ入れないとデータが受け取れない模様。
+ ブラウザ起動時に送り出したcodeと、返ってきたcodeが同じだったら、アプリ内の任意の処理をします。処理後は場合によりますが、sharedPreferencesのcodeをremove（削除）します。

#SubActivityの場合
+ scheme名をAndroidManifestで指定したmyappsubにすると、SubActivityに戻ってこられます。

##参考
▼AndroidアプリをURLから起動（まこちの技術情報覚え書き） 
http://wavetalker.blog134.fc2.com/blog-entry-72.html