ionic2のionic-nativeを幾つか試してみる

# ごあいさつ

[mediba advent calendar 2016](http://qiita.com/advent-calendar/2016/mediba) 二日目担当の佐藤禎章 @medi-y-sato です。
広告システム開発部に所属していますが、担当はネイティブアプリの開発になります。

最近ハイブリッドアプリ界隈が熱くなってきているのでそちらの勉強もやっているのですが、そこで[コレは楽だー]と思ったものを今回紹介します。 ionic-native 。


# ionic2 と ionic-native

今回取り上げるのは ionic-native という仕組みです。
前提になる各技術について、簡単ですが解説しますね。


## ionic2 とは

![ionic2.png](https://qiita-image-store.s3.amazonaws.com/0/67742/f81f44a1-6e61-0502-0342-39e8820afde0.png)

[ionic 2](http://ionicframework.com/docs/v2/) とは、下記の技術を上手いこと組み合わせてネイティブアプリの開発をすごくやりやすくしてくれるフレームワークです。

* Corova
* Angular2 
* SCSS
* などなど

これに ionic-cli という開発周りをサポートしてくれるコマンドラインツール、ライブリロードを用いた開発プレビューの仕組み、洗練されたデフォルトテーマ、専用に作成されたionic系タグによるネイティブっぽいUIコンポーネントなどがそなわり ~~最強に見える~~ アプリ開発を強力にサポートしてくれます。

RSS リーダーくらいなら1日で出来ます。


### Cordova

[Cordova](https://cordova.apache.org/) は、元々は PhoneGap と呼ばれていた技術で、ネイティブアプリの中に小さなブラウザを呼び出し、その中で JavaScript を動かして制御することで、 iOS や Android など様々なプラットフォームで同じコードを動かしてしまおう、という仕組みです。

日本で有名なのは [Monaca](https://ja.monaca.io/) ですね。 Cordova に IDE を足したりプラグインを足したり mBaaS の提携を整備したりして、扱いやすい開発環境を構築しています。
このあいだ開催されていた [HTML5モバイルアプリDAY](http://techwave.jp/html5appsday) に、この Monaca を使用してフロントエンド側の開発者だけで作ったという制作事例がいくつもあって、こりゃハイブリッドアプリも普及期だなあと実感した次第です。 ~~2年前とは隔世の感~~

ちなみに Cordova 単体としてはあくまで [JavaScript+HTML]を動かすものなので、その上で何が動いているかは気にしません。
Vue.js だろうが [Enchant.js](http://enchantjs.com/ja/) だろうが、大概のものは動きます。


### Angular2

[Angular2](https://angular.io/) は、 Google が推している JavaScript の開発フレームワークです。

JavaScript のフレームワークは [React](https://facebook.github.io/react/) だの [Riot](http://riotjs.com/) だの [Vue.js](https://jp.vuejs.org/) だのと群雄割拠で、皆さんどれを選べばいいか日々頭を悩ませていると思います。
Ionic2 では Angular2 を全面採用することにしたようです。

コンポーネントベースがどうとか Angular 初代に比べて5倍速くなったとか色々ありますが、今からやる人は *[TypeScript](https://www.typescriptlang.org/) で書く必要がある* ことだけ気にしておけばいいです。
どうせどのフレームワーク使うにしたって新しい言語覚えるのに似た事になるわけですし。


### SCSS

スタイルシートにコードを書きたいとか重複する要素ををまとめて書きたいとか、ものぐさをするために生まれたスタイルシートのコンパイラです。
クラスメソッドさんの[すぐに使えるSCSS入門](http://dev.classmethod.jp/slide/scss-tutorial/)が雰囲気をつかむのに最適ですが、ぶっちゃけ *Sass/SCSS は普通の CSS そのまま書いても問題ない* ので、忘れててもいいです。


### なんかほかにもいろいろ

凄いいろんな技術を巧みにオーケストレーションしているのですが、全部説明してたら日が暮れるのでこんなもんで。



## ionic-nativeとは

[ionic-native](https://ionicframework.com/docs/v2/native/) というのは、 *スマートフォンのネイティブ機能をionicから呼び出して使えるようにしよう* という取り組みです。

大雑把に言うと、

* Cordova プラグインを
* Angular2 と TypeScript の流儀に合わせて
* promise とか Observable の元で

使える、という仕組みです。


[対応リスト](https://ionicframework.com/docs/v2/native/) を眺めてみてください。結構広範囲ですね。
JavaScript だけでは難しいような機能も、コレを使えばかなり簡単に導入できます。

とあるアプリを作るにあたって普通の Cordovaプラ グインを導入して TypeScript の型定義を読ませてどうのこうのと苦労していたのですが、先日偶然に ionic-native に同等の機能を見つけ、試しに使ってみたらすごい簡単に導入できてしまい、驚きました。
なので今回、このお手軽さを実感してもらえればと、実装サンプルを幾つか作ってみました。


# やってみたもの

実際に実装してみたものが、これらです。
動くものを下記リポジトリで公開していますので、参考にして頂ければ幸いです。
https://github.com/medi-y-sato/PluginSample

## cordova-plugin-globalization

OS でセットされているロケール情報を元に、通貨や日時などのフォーマットを得ます。
https://ionicframework.com/docs/v2/native/globalization/

### 導入方法
```sh
ionic plugin add cordova-plugin-globalization
```

### 実装方法

[コード全体](https://github.com/medi-y-sato/PluginSample/blob/master/src/pages/globalization.ts)

```typescript

    Globalization.dateToString(nowDate,{formatLength:'full', selector:'date and time'}).then(
      res=>{ this.state.push({name:'dateToString', value: nowDate + ' -> ' + res.value}) },
      err=>{ this.state.push({name:'dateToString:error', value: err})}
    )
```

基本的に各機能を呼び出し、 then で結果を受け取る流れです。
他のプラグインも大概はこの流れで書きます。

### 実行イメージ

![SocialSharing iOS](https://github.com/medi-y-sato/PluginSample/raw/master/docs/img/globalization_ios.png "iOSイメージ")
![SocialSharing Android](https://github.com/medi-y-sato/PluginSample/raw/master/docs/img/globalization_android.png "Androidイメージ")

### 注意点

コレに限ったことですが、 2016-11-29 時点での ionic-native では numberToString() の扱いに間違いがあり、 number パラメータを渡そうとすると型チェックに引っかかってコンパイルできません

* `node_modules/ionic-native/dist/es5/plugins/globalization.d.ts`
* `node_modules/ionic-native/dist/esm/plugins/globalization.d.ts`

の下記部分を修正すればコンパイル通るようになります。

```typescript
- static numberToString(options: {
+ static numberToString(numberToConvert: number, options: {
```

[次のリリース向けに修正してもらえた](https://github.com/driftyco/ionic-native/issues/835)ので、そっちを待っちゃってもいいかもしれません。


## cordova-plugin-spinner-dialog
スピナー出します。はい。
https://ionicframework.com/docs/v2/native/spinner-dialog/

### 導入方法
```sh
ionic plugin add cordova-plugin-spinner-dialog
```

### 実装方法

[コード全体](https://github.com/medi-y-sato/PluginSample/blob/master/src/pages/spinner-dialog.ts)

```typescript
  SpinnerDialog.show('たいとる', ' めっせーじ')
  SpinnerDialog.hide()
```

呼ぶだけですね。

SpinnerDialog.show() へ渡す引数は

```typescript
SpinnerDialog.show(title, message, cancelCallback, iOSOptions)
```

と決まっています。こんな内容。

* `title` : タイトル ( Android のみ)
* `message` : 表示されるメッセージ
* `cancelCallback` : true だとスピナーのキャンセルができなくなる。コールバックを書いておくと、キャンセルされた時に呼ばれる
* `iOSOptions` : iOS 用のオプション

iOS オプションの例 :
```
{
  'overlayOpacity': 0.35,
  'textColorRed': 1,
  'textColorGreen': 1,
  'textColorBlue': 1
}
```

cancelCallback に無名関数置いておけば、キャンセル操作(どこかタップ)された時の処理を書けます。
ここを true にすると、アプリの方から hide() を呼ばない限り何の操作も受け付けなくなってしまいますので、状態遷移は慎重に。

### 実行イメージ
![SocialSharing iOS](https://github.com/medi-y-sato/PluginSample/raw/master/docs/img/spinner_ios.png "iOSイメージ")
![SocialSharing Android](https://github.com/medi-y-sato/PluginSample/raw/master/docs/img/spinner_android.png "Androidイメージ")

### その他
そもそも ionic2 自身に [LoadingController](https://ionicframework.com/docs/v2/api/components/loading/LoadingController/)というのがあったりなんかするので、わざわざコレ使う必要はないのかもしれない....


## cordova-plugin-media-capture
メディア録音/録画系の機能を呼び出します。
https://ionicframework.com/docs/v2/native/media-capture/

### 導入方法
```sh
ionic plugin add cordova-plugin-media-capture
```

### 実装方法
[コード全体](https://github.com/medi-y-sato/PluginSample/blob/master/src/pages/media-capture.ts)

```typescript
  MediaCapture.captureImage().then( res => {
    this.result = res
  })
```

OS ネイティブの録音/録画/写真機能を呼び出し、結果をファイルパスのリストとして受け取る、という仕組みです。
例えばカメラの機能については [cordova-plugin-camera](https://github.com/apache/cordova-plugin-camera)というのがあったりするのですが、それに比べると出来ることは少ないです。
代わりにこちらのプラグインは、ほぼ呼ぶだけで使えます。お手軽さがいいですね。

ドキュメンテーションは [大元のプラグイン](https://github.com/apache/cordova-plugin-media-capture) を当たって下さい。
録音時の最大時間を指定できたり、連続いくつまで取得できるかを指定できたりします。

### 実行イメージ
ボタンを押したら OS の各機能が呼ばれるだけなので、省略します。


## cordova-plugin-socialsharing

いわゆる[共有]です。テキストや URL 、画像などを他のアプリに渡すための仕組みです。
https://ionicframework.com/docs/v2/native/social-sharing/

### 導入方法
```sh
ionic plugin add cordova-plugin-x-socialsharing
```

### 実装方法
[コード全体](https://github.com/medi-y-sato/PluginSample/blob/master/src/pages/socialsharing.ts
)

```typescript
SocialSharing.shareWithOptions(
  {
    message: <<メッセージ内容>>,
    subject: <<メールソフトへ共有したときなどに使用されるタイトル>>,
    files: ['<<共有するファイルへのパス>>', ''],
    url: <<URLを共有する再に使用>>,
    chooserTitle: '共有する:'
  },
).then(
  result => console.log(result.completed + "/" + result.app),
  msg => console.log("Sharing failed with message: " + msg)
)
```

shareWithOptions() で指定するパラメータの有無によって、送り先のアプリが自動で選択されます。
files に画像ファイルがあったら Instagram が選択肢に入る、みたいな。
また、 canShareVia() で共有先として使いたいアプリが使えるかを調べたり、 shareViaTwitter() や shareViaFacebook() のように名指しで呼び出す機能もあります。
ココらへんは OS の実装に依存するので、実機でいろいろ試してみて下さい。

実行結果は then で受け取ります。
Twitter で宣伝してくれたら ~~ガチャ券あげます~~ 「 Twitter 投稿ありがとうございます！」とメッセージ出す、とか、そういう類に使えますかね。

### 実行イメージ

![SocialSharing iOS](https://github.com/medi-y-sato/PluginSample/raw/master/docs/img/socialshare_ios.png "iOSイメージ")
![SocialSharing Android](https://github.com/medi-y-sato/PluginSample/raw/master/docs/img/socialshare_android.png "Androidイメージ")


## cordova-plugin-image-resizer
画像のリサイズが行えます。
https://ionicframework.com/docs/v2/native/imageresizer/

### 導入方法
```sh
ionic plugin add https://github.com/protonet/cordova-plugin-image-resizer.git
```

### 実装方法
[コード全体](https://github.com/medi-y-sato/PluginSample/blob/master/src/pages/image-resizer.ts
)

```typescript
ImageResizer
  .resize({
    uri: srcFilePath,
    folderName: 'PluginSamples', // required for Android
    fileName: 'pluginsamples_thumbnail.png', //required for ios
    quality: 90,
    width: size,
    height: size
  }).then(
    (filePath: string) => { this.destinationImageSrc = filePath },
    (err) => { console.error(err) }
 )
```

オプションパラメータにて入力の URL を指定します。
結果はローカルに作成されたリサイズ後のファイルへのファイルパスになります。

オプションパラメータのうち、下記のように OS 毎に必須パラメータが異なります。ご注意下さい。

* Android は folderName が必須
* iOS は fileName が必須

実装例だとスライダーを動かすたびに ImageResizer.resize() を呼ぶという乱暴な作りになっています。
スライダーぐりぐり動かすたびにファイル出力しててもったいないので、実際に使うときには確定ボタンを用意するとか工夫してみて下さい。

### 実行イメージ

![SocialSharing iOS](https://github.com/medi-y-sato/PluginSample/raw/master/docs/img/imageresizer_ios.png "iOSイメージ")
![SocialSharing Android](https://github.com/medi-y-sato/PluginSample/raw/master/docs/img/imageresizer_android.png "Androidイメージ")



# まとめ

コードをご覧頂ければ、「なんだ、大したことしてないんだな」と思われるでしょう。
それが ionic-native の優れた面だと思っています。

例えば画像のリサイズなんかすごい簡単に呼べるようになっていますが、これを JavaScript で実装したら、 img タグから読んだ画像を base64 に書き換えて、 canvas にレンダリングしてやっとリサイズ、その canvas の内容をまた base64 で読み出してimg srcに指定、みたいな、割と面倒なことを実装しなければいけません。
それがimportとメソッドコール一発。

TypeScriptの書き方がいいのもあって、こんな感じでコールバック受け取っての処理が `xxx.yyy().then( res => { zzz } )` なんて感じであっさり書けてしまうのも、見通しが良くて嬉しいです。


ionic2 自身のまとまりの良さ、 Angular2 + TypeScript のパワフルさ、どちらもアプリ開発を強力に後押ししてくれると思います。
今からハイブリッドアプリ開発を検討するのであれば、 Ionic2 、オススメですよ。