Ionic3でInAppBrowserを使ってみる

# はじめに
最近ionic3を触る機会があり、その中でWebViewを実装することがありました。
が、基本的にionicのドキュメントは英語のみ、問題が起こってもほとんどstackoverflowとかgithubのissueを見て解決しなければならない…といった具合になかなか思うように進まず苦しい思いをしました:sob:
そこで今回は、実際にionicでWebViewを実装する際に調べたことを共有していこうと思います。

# 注意事項
ionicがどういったもの？、Cordova、WebViewって？といったことは省略させていただきます💦
またNode.js, ionic, cordova等のインストールが済んでいる前提で進めていきます。

# InAppBrowserとは
> Launches in app Browser

ionicのアプリ内でwebページを開くための機能になります。(そのまんま)

# インストール
```
$ ionic cordova plugin add cordova-plugin-inappbrowser
$ npm install --save @ionic-native/in-app-browser
```
**プラグインとモジュール両方のインストールが必要です！**
ちなみに僕は上記コマンドのどちらかでいいんだろうなと勝手に判断して`npm install npm install --save @ionic-native/in-app-browser`のほうだけやったら一応webページが表示されるのですが、後に出てくる`target`に`_blank`を設定しても意図した動きをしてくれませんでした:sweat:
後にプラグインのインストールが必要とわかり入れたところ、うまく動くようになりました。
(cordovaがベースとあるんですから当然ですね…:dizzy_face:)

# 初期設定
以下のようにapp.module.tsに追加していきます。

``` app.module.ts
import { InAppBrowser } from "@ionic-native/in-app-browser"; // ← 追加！

@NgModule({
    (省略)
    providers: [
        StatusBar,
        SplashScreen,
        { provide: ErrorHandler, useClass: IonicErrorHandler },
        InAppBrowser // ← 追加！
    ]
})
```

# 使い方
表示させたいコンポーネントファイルに以下のように実装していきます。
※今回の例ではngOnInitに実装してますが、イベント発火時でも実装できます。そこはよしなに:v:

```hoge.ts

import { Component, OnInit } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { InAppBrowser } from "@ionic-native/in-app-browser"; // ← 追加！

@IonicPage()
@Component({
    selector: 'page-hoge',
    templateUrl: 'hoge.html',
})
export class hogePage implements OnInit {

    constructor(
        public navCtrl: NavController,
        public navParams: NavParams,
        private inAppBrowser: InAppBrowser // ← 追加！
    ) { }

    ngOnInit() {
        const browser = this.inAppBrowser.create('https://hogehoge.com', '_blank', { location: "no", zoom: "no"});
    }
}
```
では順に実際に処理を見ていきましょう:kissing_closed_eyes:

# InAppBrowser.create( url, target, options)
このメソッドで実際にInAppBrowserのインスタンスを生成し同時に**webページの表示まで行います**。
引数は以下の通り

| 引数 | 型 | 詳細 | 
|:----|:----|:----|
| url|string| 表示するページのURL |
| target|string|URLを表示させるブラウザを指定できる。ターゲットに関しては後述。デフォルトでは`_self`|
| options|InAppBrowserOptions|InAppBrowserのオプション。デフォルトは`location= "yes"`|
`options`の`InAppBrowserOptions`型に関して、オプションを直接引数に渡すのであれば例のように`{location: "yes"}`で問題ないのですが、例えば変数に切り出して実装したいというときに型の指定で必要になります。

``` hoge.ts
// InAppBrowserOptionsを追加！
import { InAppBrowser, InAppBrowserOptions } from "@ionic-native/in-app-browser";

(省略)

const url: string = 'https://hogehoge.com';
const target: string = '_blank';
const options: object = { ... }; // ← コンパイルエラー
const options: InAppBrowserOptions = { ... }; // ← OK

const browser = this.inAppBrowser.create(url, target, options);
```


## targetについて
webページを表示するターゲットは3種類あります。

| ターゲット |  詳細 | 
|:----|:----|
| _self|URLがホワイトリストに追加されている場合はcordova browserで、それ以外ではInAppBrowserのブラウザで開く|
| _blank|InAppBrowserのブラウザで開く|
| _system|システム標準のブラウザを開く(chrome, safari等)|

例えばAndroidでwebページをchromeを立ち上げずにアプリ内で開きたいという場合には`_blank`を使用します。
~~また後で説明しますが`executeScript()`は**`_blank`でしか実行することができません。~~
**※`_self`でもできました💦**
(すみません、insertCSSは未確認です…。💦確認次第反映させます。)

# InAppBrowserのメソッド
### create(url , target, options)
先ほども説明しましたが、`URL`、`target`、`options`を設定して実際にwebページを表示させます。

### show()
InAppBrowserウィンドウを表示させます。既に表示されている場合は表示されません。

### close()
現在表示されているInAppBrowserを非表示にします。既に非表示の場合は何もしません。

### executeScript(script)
##### 戻り値：Promise< any >
InAppBrowserに実行するJavascriptのコードを注入します。
引数はobject型で渡します。コードを直接書けますし、外部ファイルを読み込ませることも可能です。
~~※`executeScript()`を使用する場合は`create(url, target, options)`の`target`が`_blank`である必要があります。~~
**※`_self`でもできました💦**

``` js
executeScript({code: "alert('Hello Ionic!');"});
```

### insertCSS(css)
##### 戻り値：Promise< any >
InAppBrowserウィンドウにCSSを注入します。
executeScriptのCSS版と思っていただいて大丈夫です。こちらも同じようにコードまたは外部ファイルを使用することができます。

### on(event)
##### 戻り値：Observable< InAppBrowserEvent >
InAppBrowserのイベントによって処理のタイミングを設定します。
イベントは4種類用意されています。

| Param | Details |
| :---- | :---- |
| loadstart | ページの読み込みが始まったら |
| loadstop | ページの読み込みが終わったら |
| loaderror | ページの読み込み中にエラーが起きたら |
| exit | ブラウザを閉じたら |

# InAppBrowserOptions
InAppBrowser.createのoptionsに設定できるプロパティです。
が、長いのでゆっくり更新していきます:sob:
 [Ionic InAppBrowser Options](https://ionicframework.com/docs/native/in-app-browser/#InAppBrowserOptions)
※一部は直訳していたり適当に書いている部分もありますが許してください！なんでもしますから！

| Param | Type | Details | OS |
| :---- | :---- | :---- | :---- |
| location | 'yes' or 'no' | InAppBrowserのロケーションバーの表示、非表示を設定する。(任意設定) | |
| hidden | 'yes' or 'no' | (任意設定) ||
| clearcache | 'yes' | `yes`を設定すると新しいウィンドウを開くときにクッキーとキャッシュをクリアする。||
| clearsessioncache | 'yes' | (任意設定) ||
| closebuttoncaption | string | (任意設定) ||
| closebuttoncolor | string | (任意設定) ||
| zoom | 'yes' or 'no' | ブラウザのズームコントロールの表示非表示を設定する。デフォルトは`yes` | Android |
| hardwareback | 'yes' or 'no' | (任意設定) ||
| mediaPlaybackRequiresUserAction | 'yes' or 'no' | `yes`に設定するとHTML5オーディオまたはビデオが自動再生されなくなる。デフォルトは`no` ||![qiita.JPG](https://qiita-image-store.s3.amazonaws.com/0/316318/7f7d54d5-e0b2-d57c-5aea-24beb9f8c847.jpeg)
| hidenavigationbuttons | 'yes' or 'no' | (任意設定) | |
| hideurlbar | 'yes' or 'no' | (任意設定) ||
| navigationbuttoncolor | string | (任意設定) ||
| toolbarcolor | string | (任意設定) ||
| shouldPauseOnSuspend | 'yes' or 'no' | InAppBrowser WebViewでバックグラウンドオーディオを停止するためにアプリを一時停止/再開させるには`yes`に設定する。 ※GooglePlayで利用規約違反になる問題があるため。| Android |
| footer | 'yes' or 'no' | `yes`に設定すると、iOSの完了ボタンと同様にフッターに閉じるボタンが表示される。そのため`closebuttoncaption`と`closebuttoncolor`を使用してプロパティを設定する。 | Android |
| footercolor | 'string' | `# 00ff00`などの有効な16進数の文字列に設定するとフッターの色がデフォルトから変更される。`footer`を`yes`に設定している場合のみ適用される。 | Android |
| disallowoverscroll | 'yes' or 'no' | UIWebViewBounce(rubber-band)を使用するか設定する。 | iOS |
| toolbar | 'yes' or 'no' | InAppBrowserのツールバーの表示、非表示を設定する。デフォルトは`yes` | iOS |
| toolvartranslucent | 'yes' or 'no' | ツールバーを半透明にするかしないかを設定する。ツールバーが設定されているときのみ。デフォルトは`yes`  | iOS |
| enableViewportScale | 'yes' or 'no' | メタタグによるビューポートの拡大縮小を防止する。 | iOS |
| allowInlineMediaPlayback | 'yes' or 'no' | (任意設定) | - |
| keyboardDisplayRequiresUserAction | 'yes' or 'no' | Javascriptのfocus()呼び出しでフォーカスが当たったときにキーボードを開くには`yes`を設定する。 | iOS |
| suppressesIncrementalRendering | 'yes' or 'no' | レンダリングする前に全ての表示内容が受信されるまで待機する。デフォルトは`no` | iOS |
| presntationstyle | 'pagesheet' or 'formsheet' or 'fullscreen' | プレゼンテーションスタイルを設定する。デフォルトはフルスクリーン  | iOS |
| transitionstyle | 'fliphorizontal' or 'crossdissolve' or 'coververtical' | トランジションスタイルを設定する。デフォルトは`coververtical`  [ここわかりやすい](https://qiita.com/osamu1203/items/6c203f3f048f9d7540f3) | iOS |
| toolbarposition | 'top' or 'bottom' | ツールバーの位置を設定する。デフォルトは下  | iOS |
| hidespinner | 'yes' or 'no' | ローディングインジケーターの表示、非表示を設定する。 | iOS |
| fullscreen | 'yes' | (任意設定) ||
| useWideViewPort | 'yes' or 'no' | `viewport`HTMLメタタグのサポートの有効無効を設定する。`yes`でページにビューポートメタタグが含まれる場合、指定された幅の値が適用される。ページにメタタグが無いか、幅が指定されていない場合はワイドビューポートが適用される。デフォルトは`yes`  | Android |

# ユースケース
>ネイティブ側でCognitoを利用しサインインまでを行い、サインイン完了後以降はCloudFrontにあるページをWebviewで表示したい。

この時、サインインで取得したトークンをWebViewのページに渡すにはどうしたらよいでしょうか？
このケースのように**ネイティブからWebviewへ値を渡したい**ときは**`executeScript()`**を利用します:laughing:

実装例はこちら

```hoge.ts

const browser = this.inAppbrowser.create(url, target, options);
browser.on('loadstop').subscribe(event => {
    browser.executeScript({ code: "sessionStorage.setItem('hoge', 'piyopiyo');"});
});
```

まず基本である`create`をします。~~繰り返しますが`target`は`_blank`で設定してください。~~
次にイベントを設定します。表示先webページの読み込みが完了したら指定したJavascript、ここではSessionStorageに値を入れる処理をしていますが、これを実行します。
こうすることで、ネイティブ側で保持している値をWebview側に渡すことが出来ます。
※ちなみに`on().subscribe()`は**Android端末またはiOS端末でしか動作しません。**ブラウザで動作を確認しようとするとエラーが出ます。

余談ですが僕は実装当初

```js
browser.executeScript({ code: `SessionStorage.setItem('hoge, ${this.hoge}');`});
```
このようなことをしていましたがうまく値渡しができませんでした。いろいろ調べてはみたのですがどれも解決に至らず…。
約１日ほど悩みました。が、なんと

```js
browser.executeScript({ code: `SessionStorage.setItem('hoge', '${this.hoge}');`});
```
このように`${}`をシングルクォーテーション囲んでいなかったのが原因でした。
こんなのにハマって１日無駄にしたのが情けない情けない…。
もしかしたら僕以外にハマる方がいらっしゃるかもしれないので一応これも共有しておきます…。

# さいごに
エンジニアが学ぶべき言語は**英語**(確信)

# 参考リンク
[Ionic native InAppBrowser](https://ionicframework.com/docs/native/in-app-browser/#InAppBrowserOptions)
[apache/cordova-plugin-inappbrowser github](https://github.com/apache/cordova-plugin-inappbrowser)
※あとから追記していきます。