use_of_void_result
このようなエラーメッセージが出ます。
This expression has a type of 'void' so its value can't be used. Try checking to see if you're using the correct API; there might be a function or call that returns void you didn't expect. Also check type parameters and variables which might also be void.
詳細は下記に書いてはありますが、わかりづらいです。
https://dart.dev/tools/diagnostic-messages#use_of_void_result
具体的にはこんなソースコードで発生します。
import 'package:flutter/material.dart'; void main() { runApp(MaterialApp( home: Home(), )); } class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( floatingActionButton: FloatingActionButton( onPressed: () async { await _onPressed(context); }, ), ); } void _onPressed(context) async { await Future.delayed(Duration(seconds: 1)); ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text("hello"), )); } }
こんな感じに修正すればOKです。
FloatingActionButton(onPressed: () => _onPressed(context)),
flutter_localizationsとfirebase_auth_web のintlのバージョンが合わない問題
Because firebase_auth_web 0.3.3 depends on intl ^0.16.1 and no versions of firebase_auth_web match >0.3.3 <0.4.0, firebase_auth_web ^0.3.3 requires intl ^0.16.1. And because every version of flutter_localizations from sdk depends on intl 0.17.0, flutter_localizations from sdk is incompatible with firebase_auth_web ^0.3.3. And because firebase_auth 0.20.1 depends on firebase_auth_web ^0.3.3 and no versions of firebase_auth match >0.20.1 <0.21.0, flutter_localizations from sdk is incompatible with firebase_auth ^0.20.1.
モバイルしか作ってないから、関係ないと思っている場合も、
flutter2.0からはwebがデフォルトで有効になっているみたいなので、
--no-enable-webにしても解決されない様子
ということで潔くoverrideする
dependency_overrides:
intl: ^0.16.1
firestore: arrayの中のmapの特定の要素を削除する
無効なFCMトークンを削除する処理を書こうとしたときに調べました。
https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array
import * as admin from 'firebase-admin'; // serviceAccountを取得 import { getInitializeAppOptions } from '../getInitializeAppOptions'; admin.initializeApp(getInitializeAppOptions()); const firestore = admin.firestore(); const docRef = firestore .collection('publics') .doc('map_delete_sample'); main(); async function setup() { await docRef.set({ tokens: [ { token: 'aaa', device: 'android' }, { token: 'bbb', device: 'apns' } ] }); } async function main() { await setup(); await docRef .update({ "tokens": admin.firestore.FieldValue.arrayRemove({ token: 'bbb', device: 'apns' }) }); console.log((await docRef.get()).data()); // { tokens: [ { token: 'aaa', device: 'android' } ] } } // ほかのサンプルコードと変数名とか衝突しないようにする export { }
オブジェクトそのもので比較することで削除対象を特定しているようです。
firebase messaging.sendToDevice()をsinonで置き換える
https://firebase.google.com/docs/cloud-messaging/send-message?hl=ja#send-to-individual-devices
注: 1 つのリクエストでメッセージを送信できる宛先デバイスの最大数は 1,000 台です。配列に 1,000 を超える登録トークンを指定すると、そのリクエストは messaging/invalid-recipient エラーで失敗します。
ということなので分割して送信することにしました。 分割するロジックはfor文で回す感じにしたので、無限ループが怖いので テストコードで確認しました。
他のtest spyみたいなのは使ったことがありますが、 sinonは初めてでしたが、公式のサンプルで使われていたので。
https://firebase.google.cn/docs/functions/unit-testing?hl=ja
import * as admin from 'firebase-admin'; import { messaging } from 'firebase-admin'; import MessagingPayload = messaging.MessagingPayload; import MessagingOptions = messaging.MessagingOptions; import MessagingDevicesResponse = messaging.MessagingDevicesResponse; /** * // https://firebase.google.com/docs/cloud-messaging/send-message?hl=ja#send-to-individual-devices * divisionUnit=1000 */ export async function batchSendToDevice( fcmTokens: string[], divisionUnit: number, message: MessagingPayload, options: MessagingOptions) : Promise<MessagingDevicesResponse[]> { const promises = []; for (let i = 0; i < fcmTokens.length; i += divisionUnit) { const dividedTokens = fcmTokens.slice(i, i + divisionUnit); promises.push(admin.messaging().sendToDevice(dividedTokens, message, options)); } return await Promise.all(promises); }
テストコード
import * as admin from 'firebase-admin'; import { messaging } from 'firebase-admin'; import MessagingDevicesResponse = messaging.MessagingDevicesResponse; import * as sinon from 'sinon'; import { batchSendToDevice } from './batch-send-to-device'; admin.initializeApp(); describe("batchSendToDevice", () => { it("Split logic works fine", async () => { const sandbox = sinon.createSandbox({}); const messaging = admin.messaging(); sandbox.replace(messaging, 'sendToDevice', (registrationToken, payload, options) => { const response: MessagingDevicesResponse = { canonicalRegistrationTokenCount: 1, failureCount: 0, multicastId: 1, results: [], successCount: 1 }; if (!Array.isArray(registrationToken)) { response.multicastId = Number(registrationToken); return new Promise((result, reject) => { return result(response); }); } registrationToken.forEach((e) => { response.results.push({ messageId: e }); return response; }); return new Promise((result, reject) => { return result(response); }); }); const tokens = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11']; const ret = await batchSendToDevice(tokens, 5, {}, {}); console.log(JSON.stringify(ret, null, 2)); }); });
完全なサンプル https://github.com/na8esin/firebase-practice/tree/master/functions/src
flutter web enableが切り替わらない
flutter webとスマートフォンの環境を併存したくて、 fvmを導入しましたが、うまく切り替わらず。
バージョンは切り替わるんですが、webの有効化みたいなのが
切り替わらず。
ただ、この時にflutter create . を実行してもwebフォルダーは作られず
そしたら、何をもって切り替わらないといっているかというと、 pubspec.yamlでfirebase_authのバージョンを空で設定しているとき、 バージョンが「0.6.2+1」になってしまうということです。
fvmがインストールされてない環境だと、「0.18.4+1」 になります。
ここが何を言っているかわからないと思いますが、 webが有効化されている場合、web用のfirebase_authも 一緒にダウンロードされていて、それがほかのパッケージの バージョンと整合性を取るために適切なバージョンになるということみたいです。
※今回はfirebase_messagingに引っ張られた模様
もともと、flutter configはプロジェクトが変わったとしても、 一律で下記の設定を見てしまいます。(windows)
~\AppData\Roaming\.flutter_settings
ですが、ここで、"enable-web": false,にしても、
設定を消しても切り替わらず。
fvmは別の設定を見ているのか、どっかでキャッシュしているのか?
もちろん、fvmを削除すると、webはfalse状態になります。
というか、クリーンな環境で再度やってみましたが、 masterだとそもそもflutter createすると webフォルダが作成される。。。
新しすぎると、webがfalseにできないか、 明示的にfalseにするしかないのか?
1.27.0-5.0.pre.95の段階では、webをfalseにすると createした時にwebフォルダはできない様子。
wslにflutterをインストールして同居する戦略
~$ sudo snap install flutter --classic Interacting with snapd is not yet supported on Windows Subsystem for Linux. This command has been left available for documentation purposes only.
というわけでwget
ここで、テストするときchromeとかどう立ち上げるんだと 思って、この方法は見送り。
結局、fvmは使わない
windowsはいろいろハマって面倒、
github.com
特にCan't load Kernel binary: Invalid kernel binary format version
なので、直接flutterを2バージョンダウンロード ※stableと1.24.0-10.2.pre
stableはgit pullで1.24.0-10.2.preはzipでダウンロード
stableにはパスを通しておく
環境変数でpath設定をします。
設定しないでフルパスでflutter configなどを実行すると、 別windowが立ち上がって実行結果がすぐに消えるので。
この状態だと何とか安定していて、androidのエミュレータと chromeを別々のvscodeから開いて実行可能になりました。
蛇足: ちなみに、別windowをpowershellで回避してみる
Start-Process -NoNewWindow -Wait -ArgumentList config C:\src\flutter\flutter_windows_1.24.0-10.2.pre-beta\bin\flutter.bat
長い。。。
.mocharc.jsのspecを設定するとコマンドラインでパスを与えたときに追加される
この辺りに書いてある https://mochajs.org/#merging
例えば、こんな設定があるときに
module.exports = { extension: [ "ts" ], spec: "test/**/*.spec.ts", require: "ts-node/register" }
npx mocha "./src/*/.spec.ts" と実行してもtestディレクトリ配下のspecも実行される
進捗率・解答率
questionが全部で5問あるとして
user1
question1 TRUE
question2 FALSE
user2
question1 TRUE
question2 FALSE
question3 FALSE
user3
question4 FALSE
正答率 2/6 には意味がありそう
進捗率 6 / 15( 5 * 3 ) よりは平均2問とかのほうがよさそう