# Flutter開發之旅
在使用firebase時,會需要initializeApp,但是官方的文檔並沒有辦法直接使用,在stackoverflow查到,因為Firebase.initializeApp(),需要使用到底層的物件,這是一個異步方法,因此我們需要確保初始化被確實執行。
需要這樣寫
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
https://stackoverflow.com/questions/63873338/what-does-widgetsflutterbinding-ensureinitialized-do
但我這樣用也可以XD,不知道是不是他有handle
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
## google sign in 註冊to firebase,使用emulator。
4/2 終於搞定了登入註冊的問題,搞了整整3天....結果問題是localhost權限忘記打開。

總結一下遇到的所有問題:一開始想說用firebase來當作資料庫,建立帳號登入系統,但是得要使用3個有點不相關的套件合作才能達成。
1. firebase_core
1. firebase_auth
1. google_sign_in
三個分別是什麼呢 ?
### firebase_core
firebase_core是用來讓dart與firebase套件能運作的整合API,在使用一切firebase操作之前必須call firebase_core的初始化函數:
```
Firebase.initializeApp();
```
有許多call法:
1. 使用future來確保初始化完成,才建立widget
```
@override
Widget build(BuildContext context) {
return FutureBuilder(
// Initialize FlutterFire
future: Firebase.initializeApp(),
builder: (context, snapshot) {
// Check for errors
if (snapshot.hasError) {
return Container(
color:Colors.green
);
}
// Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
return MaterialApp(
title:'Google Sign In',
home: SignInDemo(),
);
}
// Otherwise, show something whilst waiting for initialization to complete
return Container(
color:Colors.purple
);
},
);
}
```
2. 在main()函數中使用,但需要call ```WidgetsFlutterBinding.ensureInitialized();```
```
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
```
這是使用底層API去呼叫flutter必須先完成初始化任務才能繼續執行。詳細說明在stackoverflow有解釋:https://stackoverflow.com/questions/63873338/what-does-widgetsflutterbinding-ensureinitialized-do
### firebase_auth
firebase_auth是firebase Authentication的API,負責進行Authentication的資料與認證,是一個註冊和登入的interface。
這幾天主要也是卡在這個地方...
大概用法是
```
FirebaseAuth auth = FirebaseAuth.instance; //先建立一個instance
auth.Method() //即可執行auth的相關操作。
```
詳閱api文檔 :
https://firebase.flutter.dev/docs/auth/overview
底下是登入註冊方法的範例:
```
Future<void> _handleSignIn() async {
try {
final googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser!.authentication;
// Create a new credential.
final googleCredential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// Sign in to Firebase with the Google [UserCredential].
final UserCredential googleUserCredential =
await auth.signInWithCredential(googleCredential);
上面這一行使用google的Credential來進行註冊firebase認證。
} catch (error) {
print(error);
}
}
```
然後主要有一個問題:我如果只想要在測試環境底下操作而不是生產環境,則必須建立一個firebase emulator。
使用法:
```
class SignInDemoState extends State<SignInDemo> {
GoogleSignInAccount? _currentUser;
String _contactText = '';
FirebaseAuth auth = FirebaseAuth.instance; //這裡先建立一個instance
@override
void initState() {
super.initState();
auth.useEmulator('http://localhost:9099'); 在initState的地方打上這行
,即可將操作轉為對emulator使用。文檔的要求只有在操作以前call他就好
底下省略...
```
在這裡其實有一個問題存在如果我在非function的地方寫**auth.useEmulator('http://localhost:9099');**
其實類別會無法辨認**auth**是什麼,所以Scope要嚴格。
### null Safety
在新的google sign in API裡必須要有null Safety保護變數不是null。因此要在變數上加入保護機制才不會報錯。
比如這行,googleUser後面有一個 !
GoogleSignInAccount? account 有一個?
```
final GoogleSignInAuthentication googleAuth = await googleUser!.authentication;
_googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount? account)
```
### google_sign_in
google官方的東西就是特別嚴謹... 很多資訊你是沒辦法從原始碼讀懂的,以及一些東西甚至涉及到設備原生操作,基本上是一個黑盒子。
這段可以呼叫google的登入流程。
```
final googleUser = await _googleSignIn.signIn();
```
我是這樣發現的:只有在完成一切登入過程後console才會print出來*signin玩了喔*,由此證明整個過程google_sign_in API已經幫我們搞定了
```
final googleUser = await _googleSignIn.signIn();
print('signin玩了喔');
```
## FireStore
4/5 今天在使用firestore的時候居然報了一個錯誤Error while merging dex archives: The number of method references in a .dex file cannot exceed 64K.
意思是說我的程式裡頭import了超過64K數量方法的檔案。看來firestore有夠大的...
查了一下發現官方有提到如何規避
为方法数超过 64K 的应用启用 MultiDex
https://developer.android.com/studio/build/multidex
在./app/build.gradle裡面加上


~~wwwwwww 還沒結束,今天還遇到一個問題...花了7小時去查...完全沒找到任何討論,結果是emulator初始化忘了打
~~我把firebase init emulators
一直打錯成firebase init
~~以至於完全沒寫入到emulator上,雖然我不知道為什麼這樣在使用真實的firestore上有問題。。。~~
~~
hi 4/7 這個問題又發生了,貌似並非少打emulators的問題,而是android模擬器髒掉了.... 重新砍掉再開一個新的第一次就成功了。
6/1. Localhost請求
一般來說,只有在測試階段才會對localhost去做請求,但是這時候會出現錯誤,原因有兩個:必須要在
1. 對localhost請求的網址必須從 http://localhost 變為 http://10.0.2.2
2. 必須要在debug/AndroidManifest.xml中添加以下:
<application android:usesCleartextTraffic="true">
<!-- possibly other elements -->
</application>
寫法紀錄
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView(
children: [
for (var book in books)
ListTile(
title: Text(book.title),
subtitle: Text(book.author),
onTap: () => onTapped(book),
)
],