【Flutter】MethodChannelでSquareアプリを呼び出す
MethodChannelとは?
FlutterのDart環境からネイティブ(Android / iOS他)のメソッドを呼び出したり、その逆を行うためのAPI。
やりたいこと
- POSアプリからSquareを開いて決済したい
- Reader SDKは使いたくない
前提
あらかじめSquare Developer Portalでアプリを作成してください。作成したアプリのProductionの方のアプリIDをメモしてください。
また、作成したFlutterアプリのパッケージ名及びSHA-1のFingerprintをPoint of Sale API
に追加してください。
実装
今回はAndroid端末で動かせるように実装していきます。
コードについては「Square APIで学ぶMethod Channel」を参考にしています。
また、openSquare
やonActivityResult
については公式サンプルを参考にしています。
依存パッケージ
Squareのpoint-of-sale-sdkが必要なので、dependenciesに追加します。
dependencies {
implementation 'com.squareup.sdk:point-of-sale-sdk:2.+'
}
Flutter側
まずは作成するMethodChannelを決めます。
static const squareChannel = MethodChannel('ezpos/square');
次に、作成したMethodChannelからopenSquare
を呼び出すようにします。
Future<void> _openSquareReaderPayment() async {
final arguments = <String, dynamic>{
'price': 500, //合計金額
'memo': '商品名やその他メモなど',
};
try {
// 決済の取引IDを取得
final transactionID =
await squareChannel.invokeMethod<String?>('openSquare', arguments);
if (transactionID != null) {
// 決済完了時の処理
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Squareでの支払いに失敗しました'),
),
);
}
} on PlatformException catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Squareでの支払いに失敗しました: ${e.message}'),
),
);
}
}
FlutterからSquareを呼び出す際は、この_openSquareReaderPayment()
を使います。
Android(Kotlin)側
android/app/src/main/kotlin/com/.../MainActivity.kt
をいじっていきます。
- 必要なパッケージのインポート
// MethodChannel用
import androidx.annotation.NonNull
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodCall
// Square用
import com.squareup.sdk.pos.ChargeRequest;
import com.squareup.sdk.pos.CurrencyCode;
import com.squareup.sdk.pos.PosClient;
import com.squareup.sdk.pos.PosSdk;
import com.squareup.sdk.pos.PosApi;
import java.util.concurrent.TimeUnit;
import android.content.Intent;
import android.net.Uri;
import android.app.Activity
-
posClient
、Result
、CHARGE_REQUEST_CODE
の定義
private val CHARGE_REQUEST_CODE = 0xCAFE; // 同じであることが確認できればなんでも良い
private var posClient: PosClient? = null;
private var fResult: MethodChannel.Result? = null;
- invokeMethodで呼び出されたときの処理
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "ezpos/square")
channel.setMethodCallHandler { methodCall: MethodCall, result: MethodChannel.Result ->
if (methodCall.method == "openSquare") {
fResult = result
val args = methodCall.arguments as Map<String, Any>
// 型チェック
if (args["price"] is Int && args["memo"] is String) {
val price = args["price"] as Int
val memo = args["memo"] as String
// posClientの初期化
posClient = PosSdk.createClient(this, "SquareのアプリケーションID")
openSquare(price, memo)
} else {
result.error("INVALID_ARGUMENT", "Invalid arguments", null)
}
} else {
result.notImplemented()
}
}
}
- Squareを開く
private fun openSquare(price: Int, memo: String) {
// リクエストの作成(日本円、noteにメモをセット)
// autoReturnで決済完了後に自動で戻す
val chargeRequest: ChargeRequest.Builder = ChargeRequest.Builder(price, CurrencyCode.JPY)
.note(memo)
.autoReturn(PosApi.AUTO_RETURN_TIMEOUT_MIN_MILLIS, TimeUnit.MILLISECONDS)
try {
// インテントの取得
val chargeIntent = posClient!!.createChargeIntent(chargeRequest.build())
// 呼び出し
startActivityForResult(chargeIntent, CHARGE_REQUEST_CODE)
} catch (e: Exception) {
fResult!!.error("ACTIVITY_FAILED", e.message, null)
}
}
- Squareから戻ってきたときの処理
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CHARGE_REQUEST_CODE) {
// 正しくデータが取得できなかった場合
if (data == null) {
fResult!!.error("INVALID_RESULT", "Invalid result", null)
return
}
if (resultCode == Activity.RESULT_OK) {
// transactionIdを取得して戻す
val res = posClient!!.parseChargeSuccess(data)
fResult!!.success(res.clientTransactionId)
} else {
val error = posClient!!.parseChargeError(data)
fResult!!.error("CHARGE_FAILED", "Charge failed", error.debugDescription)
}
}
}
動作
支払いボタンを押すとSquareアプリに遷移し、Squareで決済完了するとアプリに戻ってきます。
(今回はテストなので現金で決済していますが、Square Readerも使えるはずです)
終わりに
Square Point of Sale SDK for iOSの実装例はすぐに出てきたのですが、for Androidの実装例はほぼなかったため少し手こずりました。
Discussion