Friday, December 25, 2020

com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:

  • ประเด็นคือ Flutter เพิ่ม lib เกียวกับ QRCode Scanner

/** qrcode & barcode scanner */

/** pubspec.yaml */

qrscan: ^0.2.21

image_gallery_saver: ^1.6.7

image_picker: ^0.6.7+17

permission_handler: ^5.0.1+1

url_launcher: ^5.7.10

  • แค่เพิ่มใน pubspec บันทึก futter pub get จากนั้นจะสั้งรัน ทั้งที่เรายังไม่ได้ import เลย

import 'package:image_gallery_saver/image_gallery_saver.dart';

import 'package:image_picker/image_picker.dart';

import 'package:permission_handler/permission_handler.dart';

import 'package:qrscan/qrscan.dart' as scanner;

  • มันขึ้น error ซะงั้น

D8: Cannot fit requested classes in a single dex file (# methods: 76808 > 65536)

com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: 

The number of method references in a .dex file cannot exceed 64K.

Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html

at com.android.builder.dexing.D8DexArchiveMerger.getExceptionToRethrow(D8DexArchiveMerger.java:131)

.................................................................................

FAILURE: Build failed with an exception.


* What went wrong:

Execution failed for task ':app:mergeDexDebug'.

> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade

   > com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: 

     The number of method references in a .dex file cannot exceed 64K.

     Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html


* Try:

Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.


* Get more help at https://help.gradle.org


BUILD FAILED in 15s

[!] The shrinker may have failed to optimize the Java bytecode.

    To disable the shrinker, pass the `--no-shrink` flag to this command.

    To learn more, see: https://developer.android.com/studio/build/shrink-code

Exception: Gradle task assembleDebug failed with exit code 1

  • ตอนแรกนึกว่าเราไปแก้ไข build.gradle มั่วซะอีก แต่ไปเทียบกับโปรเจคอื่นก็เหมือนกันนะ 
  • ปัญหานี้น่าจะเกี่ยวกัน  project นี้ พัฒนาด้วย sdk ที่มีการ update น่าจะประมาณนั้น

Solved

  • ที่ไฟล์ android/app/build.gradle เพิ่ม multiDexEnabled true ใน defaultConfig

defaultConfig {

        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).

        applicationId "juuier.my_smart_app"

        minSdkVersion 16

        targetSdkVersion 28

        versionCode flutterVersionCode.toInteger()

        versionName flutterVersionName

        multiDexEnabled true

    }

Ref

  • https://stackoverflow.com/questions/46977267/com-android-builder-dexing-dexarchivemergerexception-unable-to-merge-dex-andr 

Wednesday, October 14, 2020

java.lang.NoSuchMethodError: com.intellij.ide.plugins.PluginManagerCore.loadDescriptors()[Lcom/intellij/ide/plugins/IdeaPluginDescriptorImpl;

  •  Update Android Studio จาก 4.0 มาเป็น 4.1
  • แล้วเปิดใช้งานใหม่ ขึ้น error ซะงั้น
  • แบบนี้เลย

Internal error. Please refer to https://code.google.com/p/android/issues

java.lang.NoSuchMethodError: com.intellij.ide.plugins.PluginManagerCore.loadDescriptors()[Lcom/intellij/ide/plugins/IdeaPluginDescriptorImpl;

    at com.a.a.b.b.ar.a(ar.java:121)

    at com.a.a.b.b.ar.a(ar.java:71)

    at com.intellij.idea.MainImpl.start(MainImpl.java:19)

    at com.intellij.idea.StartupUtil.startApp(StartupUtil.java:303)

    at com.intellij.idea.StartupUtil.prepareApp(StartupUtil.java:245)

    at com.intellij.ide.plugins.MainRunner.lambda$start$0(MainRunner.java:47)

    at java.lang.Thread.run(Thread.java:748)

-----

JRE 1.8.0_242-release-1644-b3-6222593 amd64 by JetBrains s.r.o

/snap/android-studio/94/android-studio/jre/jre

Solved

  • ลบ folder ตามพาธนี้เลย 
  • .local/share/google/AndroidStudioPreview4.x
  • เมื่อลบแล้วเปิด Android Studio ใหม่อีกรอบ มันจะสร้าง folder config พาธนี้ใหม่ แล้วก็ใช้ได้ปกติแล้ว

Ref

  • https://youtrack.jetbrains.com/issue/TBX-5051

Thursday, September 24, 2020

ลบ cert-name ของ Let's Encrypt by Certbot

  • ประเด็นมีอยู่ว่า
  • ลองพยายามมั่วทำ wildcard certificate ของ Let's Encrypt ด้วยคำสั่งประมาณนี้

$ sudo certbot certonly --cert-name example.com

$ sudo certbot certonly --cert-name www.example.com

$ sudo certbot certonly --cert-name *.example.com

  • ที่นี้ตอน renew มันก็สร้าง Cer สำหรับ 3 คอนฟิกนี้เลย ซึ่งเราต้องการใช้แค่ cert-name ตัว root ตัวเดียวคือ example.com
  • เราจะลบได้โดย

$ sudo certbot delete --cert-name www.example.com

$ sudo certbot delete --cert-name *.example.com

เพิ่มเติม

  • เมื่อลบแล้วมีปัญหาตอน 

sudo certbot renew --dry-run

  • แล้วมันขึ้น error ว่าประมาณว่าไม่พบพาธเมื่อ excute /etc/apache2/site-available/example.com.conf
  • แก้ปัญหาโดยแก้ไขคอนฟิกไฟล์นั้นเรื่องพาธให้ถูกต้องจบ

Ref

  • https://certbot.eff.org/docs/using.html#changing-a-certificate-s-domains

เพิ่ม Virtual Host และ เพิ่ม new domain name สำหรับ Let's Encrypt Certificate

Env

  • Ubuntu 18.04
  • Apache
  • Let's Encrypt Certificate by Certbot

เรื่องมีอยู่ว่า

  • คือตอนนี้เราใช้ https ของ Let's Encrypt อยู่แล้วของ root domain name
  • จะเพิ่ม sub domain ให้ใช้ https โดยให้ Cer ของ Let's Encrypt อีกสักตัว
  • แล้วไปสร้าง Virtual Host รองรับและตั้งค่าให้ใช้ https ได้ด้วย โดยชี้ไปพาธใหม่เลยของ sub domain นี้

Step

  • เพิ่ม sub domain ให้คอนฟิกสำหรับร้องขอ Let's Encrypt Cer โดย

$ sudo certbot certonly --cert-name xxx.go.th -d xxx.go.th,www.xxx.go.th,mail.xxx.go.th,api.xxx.go.th

-------------------------------------------------------------------------

How would you like to authenticate with the ACME CA? เลือก

1: Apache Web Server plugin - Beta (apache)

Did you intend to make this change?

(U)pdate cert/(C)ancel: u

-------------------------------------------------------------------------

  • Update cert อันใหม่สำหรับ vhost เรา
  • ซึ่งคำสั่งนี้ มี option dry-run เราจะได้ Cer ใหม่จาก Let's Encrypt เลย

$ sudo certbot renew --dry-run

  • สร้าง Virtual Host สำหรับ Sub domain อันใหม่

$ sudo mkdir /var/www/api.xxx.go.th/html

$ sudo chmod -R 775 /var/www/api.xx.go.th

$ sudo nano /var/www/api.xxx.go.th/html/index.html

  • เพิ่มโค้ดในไฟล์ index.html สำหรับทดสอบ

--------

Hello new domain name

--------

  • คัดลองไฟล์  apache config ของ domain name ปัจจุบัน หรือ จะเอาจาก default ก้ได้เหมือนกัน

sudo cp /etc/apache2/site-available/xxx.go.th.conf /etc/apache2/site-available/api.xxx.go.th.conf

sudo cp /etc/apache2/site-available/xxx.go.th-le-ssl.conf /etc/apache2/site-available/api.xxx.go.th-le-ssl.conf

  • จากนั้นแก้ไขค่าใน api.xxx.go.th.conf, api.xxx.go.th-le-ssl.conf เช่น ServerName หรือ พาธต่างๆ
  • จากนั้นเปิดใช้งาน vhost โดย

$ sudo a2ensite api.xxx.go.th

$ sudo a2ensite api.xxx.go.th-le-ssl

  • อย่าลืมตั้งค่า dns ให้ api.xxx.go.th ชี้ไอพีให้ถูกต้อง
  • ทดสอบเข้าเว็บ http://api.xxx.go.th , https://api.xxx.go.th

Ref
  • https://www.digitalocean.com/community/tutorials/how-to-set-up-apache-virtual-hosts-on-ubuntu-18-04-quickstart
  • https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-ubuntu-18-04
  • https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-18-04
  • https://certbot.eff.org/docs/using.html#changing-a-certificate-s-domains

Monday, September 21, 2020

ลองเขียน RESTful API ด้วย Python

Env

  • Ubuntu 18.04
  • Python3

Step

$ pip3 install flask

  • สร้างไฟล์เพื่อแสดงคำว่า hello word ผ่าน url http://localhost:8080

$ touch hello.py

  • รันโปรแกรมของเรา

$ python3 hello.py

  • ทดสอบใช้ crul

$ curl http://localhost:8080/

  • เราจะได้ผลลัพธ์ Hello world แสดงออกมา
  • ทดสอบ Accessing Data Using GET in REST API:

$ touch get.py

  • รันโปรแกรม
$ python3 get.py
  • ทดสอบเข้าเปิด browser แล้วเข้า http://localhost:8080/accounts
  • ผลลัพธ์ มันจะแสดง json data ออกมาประมาณนี้
  • อีกตัวอย่าง รับค่าผ่าน get เพือแสดงผลตามเงื่อนไข
  • รันโปรแกรม
  • รัน url นี้ 
$ curl http://127.0.0.1:8080/account/1
$ curl http://127.0.0.1:8080/account/2
  • ตัวอย่างสุดท้ายจาก Adding Data Using POST in REST API:

  • แล้วสั่งดูข้อมูลที่เราเพิ่มด้วย POST มันเข้ามั้ยโดย
  • http://localhost:8080/accounts

  •  ภาพประกอบทั้งหมด เอามาจากอ้างอิง อ่านไม่รู้เรื่อง ไปดูที่อ้างอิงได้เลยคับ

Ref

  • https://linuxhint.com/rest_api_python/

Rewrite URLs with mod_rewrite for Apache on Ubuntu 18.04

  • เค้ามีมาตั้งนานมากแล้วพึ่งหัดทำ RESTful service จริงๆ จังๆ ก็วันนี้
  • server เป็น ubuntu 18.04 จะทำด้วย php
  • แต่ติดปัญหาเรื่อง URL มันไม่สวยตามรูปแบบ RESTful 
  • ดูตามอ้างอิงแล้วลองมั่วๆ เอานิดหน่อยก็ได้แล้ว url rewrite
  • ในที่นี้เรามี LAMP เรียบร้อยร้อยแล้ว

Step

  • เปิดใช้งาน mod_rewrite

$ sudo a2enmod rewrite

$ /etc/init.d/apache2 restart

  • ต่อมาถ้าเราใช้ config เริ่มต้นจะอยู่ที่

$ sudo nano /etc/apache2/sites-available/000-default.conf

  • เพิ่ม AllowOverride All และ Require all granted ไปไว้ใน tag ดังตัวอย่าง

  • ตัวอย่างนี้ใช้ https ของ vhost

  • หรือถ้าเราจะใช้ใน alias เราก็เอาแค่ 


  • เราตั้งค่าด้านบนไปที่พาธใหนก็ไปเพิ่ม .htaccess ตามพาธนั้นๆ
  • เช่นเราต้องการเปลี่ยน https://myhost.com/it/jui.html (เราต้องสร้าง jui.html ไว้ตามพาธ /var/xxx/it/jui.html)
  • เราจะเปลี่ยนให้เข้าเป็น https://myhost.com/it/jui
  • ให้เราสร้าง /var/xxx/it/.htaccess แล้วเพิ่ม

RewriteEngine on

RewriteRule ^jui$ jui.html [NC]

  • เปลี่ยนสิทธิ์ให้อย่างน้อย read ได้

$ sudo chmod 444 /var/xxx/it/.htaccess

  • อีกตัวอย่างของ .htaccess เราจะแสดงค่า จาก query string เช่น https://myhost.com/it/jui.php?id=2
  • เปลี่ยนให้เป็น https://myhost.com/it/jui/2
  • ตัว .htaccess ภายใต้พาธนี้จะเป็นประมาณนี้

RewriteEngine on

RewriteRule ^jui$ juuier.php [NC]


RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^/?jui/(.*?)/?$ /jui.php?id=$1 [L]

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /jui\.php\?id=([^\&\ ]+)

RewriteRule ^/?jui\.php$ /jui/%1? [L,R=301]

Note
  • ดูจากอ้างอิงแล้วใส่แค่ AllowOverride All โดยไม่ต้องใส่ Require all granted
  • ไว้ภายใต้ root tag หรือ alias tag ก็น่าจะเพียงพอสำหรับเปิดใช้งาน mod_rewrite แล้วคับ
Ref

  • https://www.tutsmake.com/how-to-mod_rewrite-enable-in-apache-ubuntu-18-04/
  • https://www.digitalocean.com/community/tutorials/how-to-rewrite-urls-with-mod_rewrite-for-apache-on-ubuntu-18-04
  • https://hostadvice.com/how-to/how-to-enable-apache-mod_rewrite-on-an-ubuntu-18-04-vps-or-dedicated-server/
  • https://begamatan.site/2/how-to-enable-mod-rewrite-on-ubuntu-1804-lts
  • https://tecadmin.net/enable-apache-mod-rewrite-module-in-ubuntu-linuxmint/
  • https://www.taniarascia.com/rewrite-query-string-to-path-with-htaccess/

Tuesday, August 25, 2020

How to install a python library mysql-connector-python manually

  • ประเด็นมีอยู่ว่าต้องการให้ python ติดตั้ง driver mysql ไม่ได้ 
  • Ubuntu 18.04 ของ DMZ รัน pip3 install ไม่ได้ เพราะลง python-pip3 ไม่ได้ เพราะ sudo apt-get install ไม่ได้ น่าจะติด Firewall
  • แต่ Ubuntu 18.04 ของ Workstation sudo apt install และ pip install ได้ปกติ

Solved

  • ที่เครื่อง Workstation แล้วดูพาธที่มันไปโหลด lib มา
# pip3 install mysql-connector-python

  • มันเป็นพาธไฟล์ .whl ให้เรา rename เป็น .zip  

  • ข้างในไฟล์ zip เราจะได้ประมาณนี้ แตกไฟล์ไปที่ เครื่องที่ pip install ไม่ได้ ไปที่พาธนี้

/usr/local/lib/python3.x/dist-packages

  • เรียบร้อยทดสอบผ่าน
Add
  • หรือเราจะไปคัดลอก lib ใน
/usr/local/lib/python3.x/dist-packages
  • หรือใน
/usr/local/lib/python3.x/site-packages
  • ไปวางเครื่องที่ pip ไม่ได้จบคับ
  • ดูเวอร์ชั่น python ให้ตรงกันด้วย เพราะ lib มันใช้ เวอร์ชั่นของใครของมัน
  • หรือไปดูใน /usr/lib/python_x.x

Ref

Thursday, August 13, 2020

Kill process by port number Linux

  • ประเด็นคือ หัดเขียน Python network programming แบบ Server-Client
  • พอสั่งปิดโปรแกรมแต่ port มันยังถูกเปิดใช้งานอยู่เลย
  • แก้โค้ดจะรันใหม่ ก็รันบ่ได้ เพราะ port ที่จะรันถูกใช้งานอยู่ ทั้งที่เราปิดโปรแกรมนั้นไปแล้วนะ

Env

  • Ubuntu 18.04
  • Python 3 code Netword Programming

Solved

  • ตัวอย่างจะเป็นการปิด process ที่เปิด port 8888 บน TCP ให้มันเลิกทำงาน
  • user ที่ไม่ใช่ root เปิดใช้ port ให้ kill process แบบนี้

$ fuser -k 8888/tcp

  • root รันโปรแกรม ให้เราใส่ sudo นำหน้าด้วย

$ sudo fuser -k 8888/tcp

Add

  • เพิ่มเติม ถ้าเราจะ kill process ด้วย id ก็สั่งประมาณนี้ (1234 คือ process id)
  • list หา process id ทั้งหมด

$ ps -a

  • list หา process id แบบ filter by name

$ ps -a | grep "program name"

  • เมื่อเราได้ process id (PID) จากคำสั่งด้านบนแล้วก็ kill ได้เลย

$ kill 1234

$ sudo kill 1234

Ref

Wednesday, July 8, 2020

Push notify by Firebase Cloud Messaging แบบกลุ่ม (Flutter & PHP)

Flutter (NEWS คือ ชื่อ topic ที่เรากำหนดเอง)
firebaseMessaging.subscribeToTopic("NEWS");
 //firebaseMessaging.unsubscribeFromTopic("NEWS");
ยิงผ่าน PHP
ยิงผ่าน Firebase console
  • ใส่ Title และ Body กด Next
  • เลือกที่ Topic ใส่หัวข้อ อันเดียวกันกับที่เราใส่ใน app flutter ในที่นี้คือ NEWS และ กด Next
  • เลือก Now คือ จะส่งตอนนี้ และ กด Next
  • อันนี้ไม่รู้ Next อย่างเดียว
  • กด Review เลย
  • สุดท้าย Publish
  • ใน Flutter app เราก็จะได้รับ Message แล้ว
Ref

สั่งให้ส่งข้อความด้วย Cloud Messaging (Firebase Service) ด้วย PHP

Step
  • เข้าไปที่โปรเจค Firebase ที่เราได้สร้างและ ผูกกับ Flutter app เราไว้
  • เลือกที่ app ของเราเลือก
  • มันจะขึ้นฟันเฟืองเลือกซะ
  • ไปที่ Cloud Messaging มองหา  Server key
  • เราจะเอา Server key นี่แหละไปใช้ต่อใน PHP เรา
  • สร้าง Class และ function ไว้ใน Class รอนำไปใช้
  • url ที่เราจะส่งไปคือ https://fcm.googleapis.com/fcm/send
  • ใส่ server key
class FCM {
    public function send_notification($token, $payload_notification, $payload_data) {
     
        $url =
'https://fcm.googleapis.com/fcm/send';
        $server_key = "AAAAd5RlNIc:APA91bFd3DplNtHcxGIauRHHJnXXXkCak6VaM4te6IA89H4MKr-OqzlapuohWNS-4rIZgdOWQu00tlUOWXMxLP9ROCffcuXth2N7nO9-CsbEkgirwaEk35DuuXeFOg-9Oeo0XmPzEd41";
        $fields = array(
            'registration_ids' => $token,
            // 'condition' => "'logined' in topics || 'news' in topics",
            // 'to' => '/topics/news',
            'priority' => 'normal',
            'notification' => $payload_notification,
            'data' => $payload_data
        );
        $headers = array(
            "Authorization: key=$server_key",
            'Content-Type: application/json'
        );
        // Open connection
        $ch = curl_init();
        // Set the url, number of POST vars, POST data
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // Disabling SSL Certificate support temporary
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
        // Execute post
        $result = curl_exec($ch);
        if ($result === FALSE) {
            die('Curl failed: ' . curl_error($ch));
        }
        // Close connection
        curl_close($ch);
        echo $result;
    }
}
?>
  • ที่นี้เรียกใช้งาน Class ที่เราสร้างขึ้น โดยเราต้องไปเอา Token จาก app flutter เรามาใช้ด้วย เพราะเราจะส่งข้อความไป app นั้น
include("fcm.php");
/*
$token = array('TOKEN1', 'TOKEN2');
*/
$token = array(
'eRmBqU2oZrQ:APA91bEH5I-VK0rkMqrwuWaGRBWkCiWsCwJLCRTgKU3tkQG6eVQdexUOvfbO_7ET19eDHsxEj8PMWes3_slWPvFsXZOTr52Fux6Ej1nwjIQ8lHgLi_Ug4wrrSWnw4hAK3f1rj7IhuN7f');
$msg =
"ข้อความแสดงใน body";
$notification = array(
'title' =>
'ข้อความ title',
'body' => "$msg", // Required for iOS 'sound' => 'default',
'badge' => 1,
'click_action' => 'OPEN_ACTIVITY_1'
);
$data = array(
'picture_url' => 'https://xxxx/slide/uploads2/20200318141207_0183.png'
);
$fcm = new FCM();
$fcm->send_notification($token, $notification, $data);
?>
  • สั่งผ่านเว็บ ส่งสำเร็จจะได้ประมาณนี้
Ref

Flutter ทำ push notify by Firebase 2

Step
  • มองหา Cloud Messaging
  • เลือกที่ Send your first message
  • ใส่ Title และ Body ที่เราจะส่งไปที่ app เรา จากนั้นเลือก Send test message
  • จากนั้นใส่ Token key ที่ได้จาก Flutter app เรา (คือจะส่งไปให้ app ที่ใช้ token key นี้ว่างั้นคล้ายๆ ระบุตัวตน) กดปุ่ม บวก
  • ตามด้วยกดปุ่ม Test
  • ดูข้อความใน app เรา
  • และใน console terminal ของ android studio
Related

Flutter ทำ push notify by Firebase 1

  • ครั้งก่อนเขียนเกี่ยวกับการทำ push notify เมื่อเรากดปุ่มบน app เรา
  • วันนี้จะลองคือ ไม่ต้องกดปุ่มแล้วสั่ง online มาแล้วให้แสดง push notify โดยใช้ความสามารถนี้ผ่าน Firebase service (Cloud Messaging)
Pre
  • ก่อนอื่นเลยอย่าลืม add Firebase config ใน Flutter 
  • ขั้นต่อไป คือเตรียมโค้ดทำ Local push notify เตรียมไว้รอ
  • จากนั้นมาเพิ่มส่วนโค้ดเกี่ยวกับ firebase messaging กัน
Step
  • เพิม dependencies firebase_massging กับ firebase_core ใน pubspec.yaml
  • ตามด้วยคำสั่ง flutter pub get
  • import firebase_messaging.dart
  • ประกาศตัวแปร FirebaseMessaging
  • ที่นี้เพิ่มโค้ดเกี่ยวกับรอรับ Messaging จาก Firebase ประมาณนี้ (โค้ดเดิม Local push notify คงไว้)
initFirebaseMessaging();


void initFirebaseMessaging() {
    firebaseMessaging.configure(
      onMessage: (Map message) async {
        print("onMessage: $message");
        Map mapNotification = message["notification"];
        String title = mapNotification["title"];
        String body = mapNotification["body"];
        sendNotificationOnline(title: title, body: body);
      },
      onLaunch: (Map message) async {
        print("onLaunch: $message");
      },
      onResume: (Map message) async {
        print("onResume: $message");
      },
    );
    firebaseMessaging.requestNotificationPermissions(
        const IosNotificationSettings(sound: true, badge: true, alert: true));
    firebaseMessaging.onIosSettingsRegistered
        .listen((IosNotificationSettings settings) {
      print("Settings registered: $settings");
    });
    firebaseMessaging.getToken().then((String token) {
      assert(token != null);
      print("Token : $token");
    });
  }
  • สร้าง sendMessaging สำหรับทำงานเมื่อ Message เข้ามาใน onMessage

  • ถ้าลองรันดูแล้ว รันได้แต่ exception ประมาณนี้
[firebase_core_web , firebase_auth_web, cloud_firestore_web ] 
  • เข้าไปแก้ไขที่ android -> setting-gradle
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
    include ":$name"
    project(":$name").projectDir = pluginDirectory
}
  • ทดสอบรันอีกครั้งถ้าสำเร็จเราจะได้ Token key จาก Firebase แบบนี้ ในหน้าต่างด้านล่าง
Ref

Popular Posts