PhoneGapBuildでアプリ内課金plugin利用

#はじめに
前回[（記事はこちら）](https://qiita.com/damacchi/items/fd66d76455ee0176eee4)にて、ひたすらIISサーバで開発したJavaScriptアプリを何とかPhoneGapBuildしたところまでたどり着いた。
ここまで来たらアプリ内課金までやってみようということで調べたけど、これまた日本語のドキュメントがなかったり古かったり。
もともとはクレジットカード決済機能をつけたかったがハードルが高いということも分かった。
よって、吐き出しておきます。

#まとめると
・クレカ決済って審査があり個人だといろいろハードルが高い。
・PhoneGapBuild Cli-7.0.1（2018/2/5時点）でないとダメ。cli-8.0.0はNG。
・開発者用googleアカウントはあったほうがいい。
・案外cordova-plugin-purchaseのドキュメントがコンパクトで必要十分。英語だけど。
・購入した後aws cognito userpoolのユーザ属性値の変更する、ということもできました。

#前提
前回と同じですが、簡単に記載します。
・riot.js,phina.jsでフロントエンドを構築
・DBはawsのdynamoDB
・認証はawsのcognito userpool
・phonegapでリリースして、手元のandroid端末での動作は確認した。
（iOS環境がないのでiOSでの動作確認はできてません。）

#クレカ決済って
アプリに対してお気持ちをいただけるなら…クレジットカードによる決済がいいかなと思ってました。
多少手数料取られてもそれが手軽なのかなぁと。
具体的には[pay.jp](https://pay.jp/)を利用しようかと思ってました。
実装は簡単そうでしたが、やめました。
理由は[個人でクレカ決済するには審査がなかなか面倒であること](http://payjp.helpscoutdocs.com/article/56-specified-commercial-transaction-law)。
無知なもので…今回勉強になりました。
2018年から提供された[PAYID](https://id.pay.jp/)も面白そうですが、今回はあきらめることにしました。

#他に送金方法って…
アプリ内課金するならプラグインを読み込んだり…が面倒そうに思えたので、そこまでしなくても済む方法はないか！と思って思案したところ、[Amazonギフト券(Eメールタイプ)](https://www.amazon.co.jp/dp/BT00DHI8G4)がいいかなと思いました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/219000/b3814561-323b-97b0-7dbe-83339eb81539.png)
受取人のところにメアドをいれていただければいいわけで。

#[Amazonギフト券(Eメールタイプ)](https://www.amazon.co.jp/dp/BT00DHI8G4)でも満たされない
とはいえ、[Amazonギフト券(Eメールタイプ)](https://www.amazon.co.jp/dp/BT00DHI8G4)ですべてが解決するわけではなくて…
・そもそもメアドを入れさせるのはハードルが高い。
・どこからの送金なのかがわからない
・[現金化が面倒](https://urutike.com/amazon-gift-realization-2-4284)
・海外からも日本のサイトに案内する必要がある
そんなわけでアプリ内課金を検討することにしました。

#phonegapでアプリ内課金
というわけで、「phonegap アプリ内課金」でググってみたものの…
案外いい例がない。
2014年ぐらいの例だと普通にphonegapで提供されているプラグインを使えばいいというようなことが書いてあるが、今は最低限のプラグイン以外はphonegap側では用意されていない。
[過去にやった人](https://www.sandalot.com/phonegap%E3%82%A2%E3%83%83%E3%83%97%E3%83%87%E3%83%BC%E3%83%88%E6%99%82%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC%E8%A7%A3%E6%B1%BA%E6%96%B9%E6%B3%95%EF%BC%88%E4%B8%BB%E3%81%ABandroid%E5%90%91%E3%81%91/)も苦労している様子。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/219000/1a0c80ca-56ac-35be-e2df-c13182e0da97.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/219000/2a1ebba3-e140-5382-33f7-088a073b0b6b.png)

キーワードを「phonegap plugin 課金」に変更するとやっと…
[ionicハイブリットアプリでアプリ内課金を実装してみよう](https://sndbox.jp/websystem-develop/mobile-app-develop/cordova-plugin-purchase)
という例があり、そこで初めて
[cordova-plugin-purchase](https://github.com/j3k0/cordova-plugin-purchase)
にたどり着く。

cordovaとphonegapは似て非なるところがあるので不安だったが…
[ちゃんと記載がある！](https://github.com/j3k0/cordova-plugin-purchase#install-the-plugin-phonegap-build)

で、よろこんでconfig.xmlに入れてみた。上記ページの例はversion6.0.0だが、最新（2018/1時点）では7.1.0なので下記の通り。

```xml:config.xml(NG)
    <preference name="phonegap-version" value="cli-8.0.0" />
    <gap:plugin name="cc.fovea.cordova.purchase" source="npm" version="7.1.0">
       <param name="BILLING_KEY" value="MIIB...."/>
    </gap:plugin>
```


しかし
![image.png](https://qiita-image-store.s3.amazonaws.com/0/219000/6eb64db4-c743-de85-7f6e-283b0807ba9a.png)
エラー？

```text
BUILD FAILED in 5s
 FAILED
39 actionable tasks: 39 executed
Error: /gradlew: Command failed with exit code 1 Error output:
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
/app/src/main/java/com/smartmobilesoftware/util/IabHelper.java:33: error: package com.android.vending.billing does not exist
import com.android.vending.billing.IInAppBillingService;
                                  ^
/app/src/main/java/com/smartmobilesoftware/util/IabHelper.java:102: error: cannot find symbol
    IInAppBillingService mService;
    ^
  symbol:   class IInAppBillingService
  location: class IabHelper
/app/src/main/java/com/smartmobilesoftware/util/IabHelper.java:234: error: package IInAppBillingService does not exist
                mService = IInAppBillingService.Stub.asInterface(service);
                                               ^
3 errors

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileReleaseJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

* Get more help at https://help.gradle.org

BUILD FAILED in 5s
    at ChildProcess.whenDone (/cordova/node_modules/cordova-common/src/superspawn.js:169:23)
    at emitTwo (events.js:106:13)
    at ChildProcess.emit (events.js:191:7)
    at maybeClose (internal/child_process.js:877:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:226:5)
```
ログだけ見てると単なるimportしているクラスのスペルミスっぽいけどなー
何が悪いかわからないけど、phonegapのcli-8.0.0はつい最近（2018/1）リリースなので、一つ前（cli-7.0.1）のにしてみた。

```xml:config.xml(OK)
    <preference name="phonegap-version" value="cli-7.0.1" />
    <gap:plugin name="cc.fovea.cordova.purchase" source="npm" version="7.1.0">
       <param name="BILLING_KEY" value="MIIB...."/>
    </gap:plugin>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/219000/149e4bd1-96c7-7462-08bb-876af4f4ef71.png)

今度は通った。

#実装…する前にGoogle Play Console
コンパイルが通ったところで、今度は実装…と思ったが、実際には[Google Play Console](https://play.google.com/apps/publish/)の登録と設定が必要というのが分かった。
案外[cordova-plugin-purchase](https://github.com/j3k0/cordova-plugin-purchase)のドキュメントが言葉少なめだがちゃんと書かれている。
そもそも開発者でもなかったので$25で登録しようとすると…
「別のアカウントで申請することを強くお勧めします」
というようなメッセージ（画像取っておけばよかった…）がでる。
googleアカウントを増やしたくはなかったが…まぁそこまでいうのだからと思って、別のアカウントを取得し、そちらのアカウントで開発者となることにした。
ネットで見るとJCBが使えないかのようなことが書かれているが、そんなことはなかった。
結果として正解だったと思う。本アカウントだとこれまでの積み重ねがあっていろいろしがらみも多いし、なによりテストがしにくいから（開発者自身のアカウントだとテスターになれない）。

Google Play Consoleとリリースについてはネットの情報が充実しているからここでは割愛。
[このあたり](http://taisho6339.hatenablog.com/entry/2017/12/22/002826)が最近の例としては適当だと思う。
そんなに難しくもない。
テストプレイヤーの指名とそのプレイヤーへのURL周知が面倒かな。
「オプトイン URL」を教える必要があるのだが、そこにたどり着くまでが…
（アプリを選択）→「リリース管理」→「アプリのリリース」→「アルファ版を管理」→「テスターの管理」（の右のほうにある▼）
…遠い。遠すぎる。

#実装
実装もネットでググっても例が少ない。
先に例を出した[ionicハイブリットアプリでアプリ内課金を実装してみよう](https://sndbox.jp/websystem-develop/mobile-app-develop/cordova-plugin-purchase)でも「例が少ない」と言っているし、その例もPAID_SUBSCRIPTION（定期購入）の例。
ここも[cordova-plugin-purchase](https://github.com/j3k0/cordova-plugin-purchase)のドキュメントが言葉少なめだがちゃんと書かれている。
参照すべきは「api.md」。

```md:api.md
### product types

    store.FREE_SUBSCRIPTION         = "free subscription";
    store.PAID_SUBSCRIPTION         = "paid subscription";
    store.NON_RENEWING_SUBSCRIPTION = "non renewing subscription";
    store.CONSUMABLE                = "consumable";
    store.NON_CONSUMABLE            = "non consumable";
```
ちなみに「PAID_SUBSCRIPTION」だと１回買うと二度と同じものは買えません（当たり前か）。
試してませんが「NON_CONSUMABLE」でも同じでしょう。
今回やりたいのは毎回同じものを買わせたいので、「store.CONSUMABLE」を選ぶべきと分かった。

具体的には１回購入する毎にAWSのcognitoユーザプールのカスタム属性「custom:SavePoint」の数値を+1したいので、以下のような実装となった。

```js:buy.tag.js
<book>　//riotを使ってます。
var SavePoint = '0'; //cognitoからの渡される値は文字列

    buySave(e) {
        //cognito更新内容定義            
        var params = {
            UserAttributes: [{
                Name: 'custom:SavePoint', 
                Value: (parseInt(SavePoint)+1).toString(),
            },],
            UserPoolId: awsUserPoolId, //ユーザプールID
            Username: _userName,　//ログインユーザ名
        };
        //インスタンス化
        var cognitoSP = new AWS.CognitoIdentityServiceProvider({apiVersion: '2016-04-18'});
        
        //cordova支払い
        store.verbosity = store.INFO;
        store.register({
            id:     （定義したID）,
            type:  store.CONSUMABLE,
            alias: "Add Save",　//定義したエイリアス
        });
        
        store.ready();
        
        //購入ダイアログ表示
        store.order(（定義したID）);
        //購入完了イベント
        store.when("order").approved(function(product) {
            cognitoSP.adminUpdateUserAttributes(params, function(err, data) {
                 if (err) {
                     //console.log(err, err.stack); // an error occurred
                 } else {
                     //console.log(data); // successful response
                     SavePoint = parseInt(SavePoint)+1;
                     riot.mount('book');　//riotを使っている。ここで再度マウントすることで変更内容を反映させている。
                 }
            });

            product.finish();
        });
        store.refresh();
   }
</book>
```

[cordova-plugin-purchase](https://github.com/j3k0/cordova-plugin-purchase)のサンプルに近い。もっと細かい制御もできそうだが、個人的にはこれで十分だったのでここまでとした。



#テストも若干不安だが問題はない
[Androidでアプリ内課金テストを行う](https://qiita.com/soratyan/items/91423b9d0d474cb044c7)のとおり、α版かβ版で登録して、テストユーザとして指定したユーザIDでログオンすれば課金はされない。
なんか設定することがなくて逆に不安だが、間違ってない。
[アプリ内課金のテスト](https://developer.android.com/google/play/billing/billing_testing.html?hl=ja#billing-testing-test)のとおり。
テストをすればメールもくるし。
不安だったら、取り消しすればいい。

#最後に
ネット上にありそうでなかったので、書き出してみました。
他の人の参考になれば。
そして
[Amazonギフト券(Eメールタイプ)](https://www.amazon.co.jp/dp/BT00DHI8G4)を受取人（ruzafi205@ahk.jp）にして今すぐ購入！
お待ちしてます（笑

#おまけ
##一つ目
phonegapのプラグインの導入の仕方は上記のとおりと分かったので、前回全部plugin化をあきらめたところもやり直そうかな…と思ったが、やめた。
もうコードフリーズ段階なので、あえてやる必要性がないかなと思ったのと取り込んだ外部ライブラリのファイルサイズも大きくないため。

##二つ目
とはいえawsのSDKだけは1Mbyte超えてたのでなんとかしようとしてたら
[Build your own version of the AWS SDK for JavaScript](https://sdk.amazonaws.com/builder/js/)
なるページがあり、使っているサービスだけに絞ることができた。
ありがたや。