NCMBのFlutter SDKがマルチプラットフォーム対応しました

[NCMB](https://mbaas.nifcloud.com/)ではiOS/Android/Unity/JavaScript向けに公式SDKを提供しています。しかし、それ以外にもコミュニティSDKとして幅広いプラットフォームに対してSDKを開発しています（主に私が）。これらは非公式なので公式サポートは得られませんが、[オープンなコミュニティでは質問可能](https://github.com/NIFCLOUD-mbaas/UserCommunity)です。

そのコミュニティSDKの一つとして[Flutter SDK](https://pub.dev/packages/ncmb)があります。v2.1.1まではAndroid/iOS/Linux/macOS/Windowsのみの対応となっていましたが、v2.2.0でようやくWebに対応しました。

[ncmb | Dart Package](https://pub.dev/packages/ncmb)

![ScreenShot_ 2021-12-09 16.16.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/e9af700f-8d78-f876-63e3-553e716daded.png)


今回はWeb対応するために行ったことをメモとして書いておきます。

## Webに対応していなかった理由

Flutter SDKではデータをローカルに保存する際に `shared_preferences` というライブラリを利用していました。この `shared_preferences` を使っていると、Scoreのところで次のようなメッセージが出ていました。

```
Package does not support Flutter platform `Web`.
Because:

package:ncmb/ncmb.dart that imports:
package:shared_preferences/shared_preferences.dart that imports:
package:shared_preferences_windows/shared_preferences_windows.dart that declares support for platforms: Windows.
```

とはいえ、`shared_preferences` 自体はWebにも対応しているので、flutter runでGoogle Chromeを使って開発することも可能という状態でした。開発できるし良いかなと思っていたのですが、やはりきちんと対応しておくべきと考えて修正することにしました。

## 行った修正

### partからexportに

元々機能ごとにファイルを分けて開発していたのですが、それらはすべて lib/ncmb.dart にてpartを使って読み込んでいました。

```dart
part 'src/main.dart';
part 'src/object.dart';
part 'src/request.dart';
part 'src/signature.dart';
part 'src/query.dart';
part 'src/acl.dart';
part 'src/geopoint.dart';
part 'src/user.dart';
part 'src/installation.dart';
part 'src/file.dart';
part 'src/role.dart';
part 'src/relation.dart';
part 'src/push.dart';
```

そして各ファイルでは `part of` を使っていました。

```dart
part of ncmb;
```

そして、shared_preferencesも lib/ncmb.dart の中で読み込んでいました。恐らく、これが原因です。

```dart
import 'package:shared_preferences/shared_preferences.dart';
```

[Dartのディレクティブたち](https://zenn.dev/littleforest/articles/a4fc5bc7c944d42f66d2)によると、partは一つのファイルを分割しているだけということで、`shared_preferences` を本来使っている lib/src/user.dart で読み込むように移動できませんでした。

そこで `part` をやめて、`export` を使うようにしました。

```dart
library ncmb;

export 'src/main.dart';
export 'src/object.dart';
export 'src/request.dart';
export 'src/signature.dart';
export 'src/query.dart';
export 'src/acl.dart';
export 'src/geopoint.dart';
export 'src/user.dart';
export 'src/installation.dart';
export 'src/file.dart';
export 'src/role.dart';
export 'src/relation.dart';
export 'src/push.dart';
```

### クラスの使い方変更

元々NCMBObjectを継承する形で NCMBUser や NCMBFile などがあったのですが、`part` を止めると NCMBObject（親クラス）の変数にアクセスできなくなりました。これは `this.AAA` から `super.AAA` に変更する必要があります。また、Getter/Setterを使うことで、アクセスしやすくなります。

```dart
// 変更前
Future<NCMBFile> download(String fileName) async {
	NCMBRequest r = new NCMBRequest();
	Map response = await r.exec('GET', _name!, objectId: fileName, multipart: true);
	var f = NCMBFile();
	f.set('blob', response['data']);
	return f;
}

// 変更後
Future<NCMBFile> download(String fileName) async {
	NCMBRequest r = new NCMBRequest();
	Map response =
                                // ↓ ここ
			await r.exec('GET', super.name, objectId: fileName, multipart: true);
	var f = NCMBFile();
	f.set('blob', response['data']);
	return f;
}
```

## 各ファイルで必要なファイルをインポート

`part` の場合は lib/ncmb.dart でインポートしたライブラリがそのまま使えていたのですが、import/exportにしたことで、各ファイルでライブラリを読み込む必要がありました。

こちらの方が自然な気はします。

```dart
import 'package:mime/mime.dart';
import 'package:http_parser/http_parser.dart';
import 'object.dart';
import 'request.dart';
import 'acl.dart';
import 'query.dart';
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
```

## まとめ

後はテストを実行して完了です。 `part` の方が楽ではあるのですが、今回の対応で色々手こずったのが辛かったです。ともあれ、これでNCMBのFlutter SDKはWeb環境はもちろん、iOS/Android/macOS/Windows/Linuxでも利用できるようになりました。

![ScreenShot_ 2021-12-09 16.16.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/b41b6734-4de3-cb26-1c8e-7df99c3109fb.png)

依存ライブラリがWeb対応していないといけないので、ライブラリを追加する場合には注意が必要です。NCMBのFlutter SDKでは、デバイストークンの取得などスマートフォン環境に依存するものは取り込んでいません。ちょっと面倒ではありますが、別途デバイストークンを取得するライブラリを組み合わせる必要があります。ただ、そのお陰でWeb環境でも利用できるようになっています。

スコアもだいぶ上がってきたので、ドキュメントをきちんと書いて使いやすいSDKにしていきます。ぜひお試しください。

[ncmb | Dart Package](https://pub.dev/packages/ncmb)