Flutterで秘匿情報を扱う
最近Flutterを触ってます。
Gitなどに載せたくない情報の扱い方についてのメモ。2つの方法を取り上げます。
.env + flutter_dotenv
flutter_dotenvを使います。pubspec.ymlに以下を追加して
- pubspec.yml
dependencies: .. flutter_dotenv: ^2.0.1 .. flutter: .. assets: - .env
$ flutter pub get
を実行します。
上の例ではプロジェクトルートに .envというファイルを置く想定です。
- .env
SAMPLE_VALUE=this is dot env value.
main関数のはじめに初期化します。
- main.dart
void main() async { await DotEnv().load('.env'); runApp(DotenvApp()); }
次のように呼び出します。
class DotenvApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("Dotenv App"), ), body: Center( child: Column( children: <Widget>[ Text( 'dotenv values: ${DotEnv().env["SAMPLE_VALUE"]}', ), ], ), ), ), ); } }
Map<String, String>型なので取り出して適宜キャストして利用します。
一度初期化したらどこからでも呼べます。
flutterパッケージに依存しているのでFlutter for Webでは利用できません。
JSON + json_serializable
json_serializableを使います。pubspec.ymlに以下を追加して
- pubspec.yml
dependencies: .. json_annotation: ^2.4.0 .. dev_dependencies: .. build_runner: ^1.0.0 json_serializable: ^3.0.0 .. flutter: .. assets: - secret.json
$ flutter pub get
を実行します。
上の例ではプロジェクトルートに secret.jsonというファイルを置く想定です。
- secret.json
{ "value": "secret value", "num": 20190606 }
JSONは末尾カンマを許してはくれないので注意しましょう
対応するモデルを作成します。
- secret.dart
part 'secret.g.dart'; @JsonSerializable() class Secret { final String value; final int num; const Secret(this.value, this.num); factory Secret.fromJson(Map<String, dynamic> json) => _$SecretFromJson(json); }
このままだと自動生成されたコードがないので、エラーになります。コードを生成します。
$ flutter pub run build_runner build
これでエラーは消えます。
JSONファイルを読み込んでモデルを返すクラスを用意します。
- secret_loader.dart
class SecretLoader { final String secretPath; SecretLoader({this.secretPath}); Future<Secret> load() { return rootBundle.loadStructuredData<Secret>(this.secretPath, (jsonStr) async { final secret = Secret.fromJson(json.decode(jsonStr)); return secret; }); } }
準備はできました。次のように呼び出します。
- secret_app.dart
class SecretApp extends StatelessWidget { final SecretLoader loader = SecretLoader(secretPath: "secret.json"); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("Secret App"), ), body: FutureBuilder<Secret>( future: loader.load(), builder: (context, snapshot) { if (!snapshot.hasData) { return Center( child: CircularProgressIndicator(), ); } final secret = snapshot.data; return Center( child: Column( children: <Widget>[ Text( 'secret value: ${secret.value}', ), Text( 'secret num: ${secret.num}', ), ], ), ); }, ), ), ); } }
SecretLoader#loadの返り値がFuture型なのでFutureBuilderを使ってます。
内部で保持する仕組みはないので、その他の変数と同じように呼び出したスコープ内でしか扱えません。
flutter_dotenvのときのようにmainで呼び出して、コンストラクタで必要なWidgetに値を渡しても良いと思います。
flutterパッケージに依存していないのでFlutter for Webでも利用できます。その際はJSONファイルをweb/assets/に配置します。
まとめ
どちらも一長一短あります。秘匿情報の利用が初期化時のみで済むのならJSON + json_serializableの方が、若干の準備がありますが良いかなと思いました。構造を持てるのは大きな魅力です。さっと試す程度なら.env + flutter_dotenvのほうが手軽だと思います。
どちらの方法にしても、間違えて秘匿情報を書いたファイルをコミットしないように注意しましょう。
参考
flutter_dotenv / Flutter Package
Storing your secret keys in Flutter – Sócrates Díaz Severino – / Medium
DockerHubでAutomated Buildsを使った時にDocker Tagがうまく設定できない
OpenSSLでファイルの暗号化/復号化をしたくてAlpineベースのDockerイメージを作成しました。
ググったら同じようなものがあったのですが、OpenSSLのバージョンやCA証明書が古かったりで使いにくかったので作成しました。
どのバージョンのOpenSSLが入っているか・または指定できるようにtagをつけて管理したいと思い、Automated Buildsでtagをpushした時に自動でつけられるようにしたかったのですが、ちょっとハマったのでメモ。
何をしたか
デフォルトでmasterブランチを対象に latest
とtagを振ってくれるRULESがあるのですが、今回はtag名にしたかったので不要と思い削除しました。
その上でGitのtagを見てそれをDocker Tagになるように設定したのですが、 Docker Tag
の部分がうまく指定できなくなりました。具体的には、何を入力しても latest
になります。
設定できそうに見えるのですが、保存すると Docker Tag
が latest
に置きかわります。
latest
tagを振るRULESが最低1つは必須なんだと思い、はじめにあったRULESを追加してもダメでした。
どうやら 一番上が優先される ようで、削除して latest
が一番上に来るようにRULESを指定することで思ったように指定できるようになりました。
思えば latest
のtagが振られていないものってないなと思い、それから逸脱するような指定はできないようになっているんだなと納得しました。
まとめ
- RULESは上にあるものが優先される
- latest tagの指定は必要
- 一度tagをつけてAutomated Buildsに成功した後は
latest
tagの指定を削除しても設定できるようになりました。一定の環境下でないと起きないのかもしれません。
- 一度tagをつけてAutomated Buildsに成功した後は
参考
2018年を振り返って
すでに2019年が10%以上過ぎてますが、2018年の振り返りをまとめてなかったのでまとめておきます。
はじめに目標としてたことに対して振り返ります。
目標としてたこと
- 自炊の回数を増やす
- 12月から自炊を再開しました。相変わらずパスタ一辺倒です。振り返ってみると、引っ越ししてから2年以上自炊をしてませんでした。すごい。
- 体を鍛える
- 結局何もしなかったです。しかし続きがあります。
- Android以外のこともする
- iOSアプリを作り始めたのはいいですがモチベーションと進捗の折り合いがつかず、結局頓挫しました。しかしそのときにReactorKitというFluxベースのフレームワークを使い、Fluxの世界に興味をもつことが出来ました。
- Google Assistant周りの何かをする
- Nature Remoとiftttの既成品の連携だけで、特に開発はしなかったです。
- Fitbit ionicのWatchFace作る
- 正しくはClockFaceなのですが、こちらは作ることが出来ました。追い込まれるとやっぱりやらざるを得なくなります。
結果だけ見ると着手は半分以上できてるという結果にはなりますが、個人的にはそんなにやったった感は感じてないです。むしろ出来てないなという感じです。新規アプリ開発も公開までしたものはありませんでした。
やったこと
インサイダー・ゲームの拡張を作ろうとした
インサイダー・ゲームというボードゲームがあるのですが、出現するワードがカードに書かれている限りなので、そのワードを拡張して楽しめるようにできるアプリを作ろうとしました。
- ワードの分類
- ワードの保存
- ワードを追加する機能
- 分類したワードを表示する機能
とかが必要になるので、始めにワードの分類をしようと思い、ベクトル化をするところまでやってモチベーションの灯が消えてしまいました。
DockerHubにもあげてあるので動かしてみることは出来ます。
技術書典に参加した
技術書典5に出店側として参加しました。そのときにClockFaceの作成と同人誌作成をしました。
詳細は別記事にまとめてあります。
ClockWaceを作った
技術書典で本を出すにあたり、作ってみました。当初はApple Watchという名前を入れていたのですが、ストアでレビューで落とされてしましました。一粒で二度美味しい体験ができました。
競争相手があんまりいないからか、ユーザから問い合わせがちらほらくるので、2019年はガチなやつを一つ作りたいなと思ってます。
jib触った
前述のベクトル化するコードのdocker化や、会社でのツールなどに活用しました。
Kotlin/Nativeちょっと触った
AlfredのWorkflowに使いました。多分やってる人はまだ他にいないです。
趣味とかその他
ボドゲにハマった
ハマりました。どれくらいかと言うと、自分でも買うしゲムマにも行くしボドゲを作るワークショップにも参加するくらいです。
2018年にこれだけ買いました。
- ごきぶりポーカー
- トロイカ
- ドミニオン
- ドミニオン(海辺)
- ナショナルエコノミー
- ワンナイトマンション
- パンデミック
- チケット・トゥ・ライド(ドイツ)
- ザ・マインド
- Tokyo Highway
- リキュール・ザ・ゲーム
- CESSPOOL:REMASTERED
ちなみに今年もすでに買い始めてます。
コーヒーにハマった
家で豆を挽いて飲むようになりました。スタバみたいなカフェミストを家でも飲みたいと思い、クリーマーを購入しました。
あとはマキネッタを買って、より濃いコーヒーでカフェミストを作ったりしてます。夏には水出しアイスコーヒーも作りました。
ハンドドリップ用に計りを買いましたが、安定したドリップにも貢献してくれるしそれ以外にも便利なので計りは一家に一台おすすめです。
2019年
すでにいくつか始めていることがあります。
ジム通い始めた
周りにやるって言っちゃったので勢いで始めました。今の所苦なく続いてます。会社帰りに通えるのは自分の中でマストだなと思いました。形から入るので、アンダーアーマーのコンプレッションウェアも購入してます。
競プロ始めた
基礎が弱いのはわかっていたので、学ぼうと思い始めました、筋トレと同じく、目が出たと思うタイミングが来るのかもしれません。
目標
OKRの本を読んで、会社としても導入しています。個人の目標も時期を区切って、OKRという形でやってみようかなと思ってます(すでに1ヶ月経ってるけど)。