iOS: in ios/Runner/Info.plist
ขอสิทธิ์ Location
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key><true/> </dict>
ขอสิทธิ์ใช้กล้อง
<key>NSCameraUsageDescription</key> <string>Explanation on why the camera access is needed.</string>
ขอสิทธิ์ไมโครโฟน
<key>NSMicrophoneUsageDescription</key> <string>Flutter requires acess to microphone.</string>
Android: android/app/build.gradle
defaultConfig { minSdkVersion 21
Android: android/app/src/main/AndroidManifest.xml
<application> <provider android:name="com.pichillilorenzo.flutterinappwebview.InAppWebViewFileProvider" android:authorities="${applicationId}.flutterinappwebview.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILEPROVIDERPATHS" android:resource="@xml/provider_paths" /> </provider> </application>
Create file res/values/provider_paths.xml
<?xml version="1.0" encoding="utf-8"?> <paths> </paths>
main.dart
import 'package:permission_handler/permission_handler.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); await Permission.camera.request(); runApp(MyApp()); }
สิทธิ์อื่นดูได้จาก Enable camera for HTML inputs
ที่มา
Step 1. Create a new application. The main screen in which will be StatefulWidget. Which should implement the WidgetsBindingObserver interface. Next, we get the instance of WidgetBinding and add an observer to it.
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver { @override void initState() { WidgetsBinding.instance.addObserver(this); super.initState(); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Tutorial Lifecycle'), ), body: Center(), ); } }
Step 2. Now we have the didChangeAppLifecycleState method available. In this example, we simply print a state change to the thermal.
@override void didChangeAppLifecycleState(AppLifecycleState state) { print('state = $state'); }
ที่มา Flutter App Lifecycle
เขียน Flutter App
Create new app
flutter create --org com.yourdomain appname
Android หากมี error gradle ให้แก้ไขไฟล์ android > gradle > gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
Set App signing team to your email
Open app using VSCode and run
Then build iodopen ios/Runner.xcworkspace
flutter build ios
In Runner / Targets/Runner -> select Team
If have already created a project: Change package name by add dependencies changeapppackagename: and run
apppackagename:main com.package.appnameflutter pub run change
Run in release mode
flutter run --release
Settings
- เปลี่ยนชื่อ App Icon
- Add permission: กำหนด Permission ด้วยนะ ไม่อย่างนั้นจะเปิด WebView เข้าเน็ตไม่ได้
iOS: แก้ไขไฟล์ ios/Runner/info.plist
<key>CFBundleName</key> <string>APP NAME</string> <key>io.flutter.embeddedviewspreview</key> <string>YES</string>
Android manifest: แก้ไขไฟล์ android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" /> <application android:label="APP NAME" >
macOS: in macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements
<key>com.apple.security.network.client</key> <true/>
App Icon:
File : pubspec.yaml
dependencies: ... flutter_launcher_icons: ^0.9.0
flutter_icons:<br /> image_path: "assets/icon/logo_192.png"<br /> android: true ios: true remove_alpha_ios: true
# dart run flutter_launcher_icons:main
เอาคำว่า "DEBUG" ของเธอคืนไป
ใส่ไว้ใน MaterialApp
debugShowCheckedModeBanner: false
Add dependencies แล้ว แต่ import package ไม่ได้
close project and re-open projectflutter packages get
Upgrade version iOS แล้วมองไม่เห็น device
ให้ดาวน์โหลดไฟล์จาก GitHub แล้วนำไฟล์มาวางไว้ที่ (~/Application/) Xcode app ใน path Contents/Developer/Platform/iPhoneOS.platform/DeviceSupport
แล้วก็ Flutter Clean
flutter clean
App Permission
หัวข้ออื่น
ที่มา
- มาลองสร้าง Flutter App กันเถอะ
- ประสบการณ์ Build flutter on iOS ครั้งแรก
- webview_flutter 2.0.2
- Different ways to change the status bar and navigation bar color (iOS and Android) in Flutter
- Flutter Launcher Icons
- How to use user-agent in webview-flutter Flutter?
- Flutter webview intercept and add headers to all requests
- Webview in flutter not working getting a platform error
- Flutter BottomNavigationBar not working with more than three items
เกิดอาการนี้มาเป็นวันที่ 2 แล้ว เมื่อวานสั่ง reboot แล้วหาย แต่วันนี้ reboot แล้วยังคงมีอาการอยู่
ที่เคยเจออาการนี้ คือ harddisk เต็ม ซึ่งปกติจะตรวจพื้นที่เหลือใน harddisk ก่อน ด้วย df -h ผลออกมาว่ายังมีพื้นที่เหลืออีกเพียบ จนในที่สุดก็พบว่าที่เต็มนั้นไม่ใช่พื้นที่ แต่เป็น inode ลองตรวจดูด้วยคำสั่ง df -i พบว่า / เต็ม 100%
สาเหตุของครั้งนี้คือ inode ที่มีไว้สำหรับเก็บตำแหน่ง folder/file เต็ม เท่าที่อ่านดู ยังไม่สามารถขยายเพิ่มได้ (ต้องทำตอน format harddisk) จึงต้องค้นหาว่า folder ไหนที่มีไฟล์เป็นจำนวนมาก แล้วก็ลบ/ย้ายไปไว้ที่อื่นที่ใช้คนละ inode กัน
# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on udev 1275949 357 1275592 1% /dev tmpfs 1278745 553 1278192 1% /run /dev/sda1 1831424 1831424 0 100% / tmpfs 1278745 1 1278744 1% /dev/shm tmpfs 1278745 3 1278742 1% /run/lock tmpfs 1278745 15 1278730 1% /sys/fs/cgroup /dev/sdb1 122093568 8699755 113393813 8% /backup /dev/sda4 119996416 4748787 115247629 4% /home /dev/sda2 122400 337 122063 1% /boot tmpfs 1278745 10 1278735 1% /run/user/1004
คำสั่ง ls เพื่อดูว่าแต่ละ file มี inode หมายเลขอะไร
# ls -lai
คำสั่งสำหรับนับจำนวนไฟล์ในแต่ละ folder
# for i in /*; do echo $i; find $i |wc -l; done
# echo "Detailed Inodes usage for: $(pwd)" ; for d in `find -maxdepth 1 -type d |cut -d/ -f2 |grep -xv . |sort`; do c=$(find $d |wc -l) ; printf "$c - $d " ; done ; printf "Total: $(find $(pwd) | wc -l) "
พบว่า folder usr/local/directadmin/data/tickets มี folder/file จำนวนมาก ซึ่งสะสมมาจาก ticket ที่ระบบอัตโนมัตของ directadmin สร้างขึ้นมา จึงทำการลบไฟล์ทิ้งทั้งหมด
# rm -rm /usr/local/directadmin/data/tickets[code] แล้วย้าย folder tickets ไปไว้ใน /backup (ซึ่งอยู่คนละ harddisk ก็จะไม่มีผลต่อ inode ของ /) [code] # mkdir /backup/usr # mkdir /backup/usr/local # mkdir /backup/usr/local/directadmin # mkdir /backup/usr/local/directadmin/data # mkdir /backup/usr/local/directadmin/data/tickets [code] เปลี่ยน owner/group ให้เป็นของ DirectAdmin [code] # chown diradmin:diradmin /backup/usr/local/directadmin # chown diradmin:diradmin /backup/usr/local/directadmin/data # chown diradmin:diradmin /backup/usr/local/directadmin/data/template # chown diradmin:diradmin /backup/usr/local/directadmin/data/tickets
สร้างลิงก์ tickets ไปที่ใหม่
# cd /usr/local/directadmin/data # mv tickets tickets.old # ln -s /backup/usr/local/directadmin/data/tickets tickets # chown -h diradmin:diradmin tickets
ปล. เขาบอกว่าให้ลบไฟล์ session ทิ้งด้วย
# find . -type f -name sess_\* -delete
ที่มา
ตอนจะติดตั้ง Xcode มัน error "Not enough storage disk space, you can't install the product".
สาเหตุเกิดจาก App Store คำนวณพื้นที่ว่างผิด ได้ไม่เท่ากับพื้นที่ว่างจริง
สำรวจพื้นที่ว่างในฮาร์ดดิสกันก่อน
About this Mac > Storage
Trick คือ ให้ macOS ทำการ clean up APFS โดยสร้าง a huge garbage file หลังจากนั้นก็ลบมันทิ้งไป
สร้างไฟล์โดยคำสั่ง:
dd if=/dev/zero of=/Users/<username>/hugefile bs=100m
ปล่อยให้มันทำงานไปสัก 30 วินาที แล้วก็ kill มันทิ้งด้วย ctrl+c หลังจากนั้นก็ลบไฟล์นั้นทิ้งไป:
rm ~/hugefile
ลบ Snapshots
tmutil thinlocalsnapshots / 21474836480 4
น่าจะถึงเวลาที่ต้องมาเขียน App บน iOS เสียที มีงานรออยู่หลายชิ้นแล้ว ตั้งแต่ iMed@home, Green Smile, 1T1U และน่าจะมีตามมาอีกหลายงาน เช่น iMed@NCD Care
Set App to be a release mode (default is debug mode cannot run directly)
In VS Code Settings:
Tab User => Extensions/Dart & Flutter/Dart: Flutter Run Additional Args
or search "Flutter Run Additional Args"
Dart: Flutter Run Additional Args
Additional args to pass to the flutter run command.
Add Item --release
In command line
You can Run your application in Release Mode easily in your terminal using :
flutter run --release
And it will switch to Release Mode .
But if you don't want to run your app , just want to build your apk or ipa , Use :
flutter build --release
In X-Code
You can specify to build for ios by using flutter build ios
Follow these 3 steps:
cd project open ios/Runner.xcworkspace
- Open your Flutter project in Xcode.
- Top Bar Product > Scheme > Edit Scheme
- Build Configuration - Select Release
Note: Release type flutter app is valid for 7 days on iOS devices.
ที่มา
รอก่อนนะ ค่อยกลับมาทยอยเขียน
Edit Apache config
sudo nano /etc/apache2/httpd.conf
ServerName my.local.:80 <Directory "/"> AllowOverride All Require all denied </Directory> <Directory "/Library/WebServer/Documents"> AllowOverride All </Directory>
Restart Apache
sudo apachectl restart sudo apachectl -k graceful
Edit MariaDB config
nano ~/.my.cnf
Restart MariaDB
Auto start
brew services start mariadb
Manual start
mysql.server restart
Configuration
PHP Config
nano /usr/local/etc/php/8.0/php.ini
... post_max_size = 1024M upload_max_filesize = 1024M ...
ที่มา
แปะไว้ก่อน ค่อยมาเขียนรายละเอียดนะครับ
sudo nano /etc/php/7.4/fpm/php.ini sudo systemctl restart apache2sudo nano /etc/mysql/conf.d/mysqld.cnf sudo systemctl restart mysql
mkdir remotefolder sshfs -p 22 username@example.com:/home/folder/ remotefolder umount remotefolder
sshfs -p 22 username@example.com:/home/user/domains/example.com/public_html/ remotefolder nohup rsync -trv remotefolder/path/ path/ &
sudo apt update<br /> sudo apt upgrade
sudo apt install apache2 -y systemctl status apache2
sudo a2dismod ssl sudo a2enmod ssl<br /> <br /> <br />
apt install php7.4 php7.4-mysql php-common php7.4-cli php7.4-json php7.4-common php7.4-opcache libapache2-mod-php7.4
apt install mariadb-server mariadb-client systemctl status mariadb
mysql> CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password'; mysql> GRANT ALL PRIVILEGES ON * . * TO 'newuser'@'localhost';<br /> <br /> <br />
sudo systemctl restart apache2<br /> sudo systemctl restart mysql<br /> <br /> <br /> wget -r --ask-password ftp://user:server.com/
- https://upcloud.com/community/tutorials/installing-lamp-stack-ubuntu/?utmterm=&utmcampaign=DSA&utmsource=adwords&utmmedium=ppc&hsaacc=9391663435&hsacam=7185608860&hsagrp=81739862313&hsaad=391197952986&hsasrc=g&hsatgt=dsa-460992423274&hsakw=&hsamt=b&hsanet=adwords&hsaver=3&gclid=CjwKCAiAeb-BRB2EiwAGBnXXuae-7ru2jsgSAiku6bX0k7XucjvKLGBQkSm-DKo92SXjG1odKAeRoCid0QAvD_BwE - https://www.digitalocean.com/community/tutorials/how-to-create-a-new-user-and-grant-permissions-in-mysql - https://stackoverflow.com/questions/113886/how-to-recursively-download-a-folder-via-ftp-on-linux - https://askubuntu.com/questions/709594/how-can-i-disable-and-enable-ssl-in-apache-without-a-command-if-possible
- ต่อโทรศัพท์ Android กับ Mac ก่อน ด้วย USB Cable
- เปิด Termilal แล้ว run
Library/Android/sdk/platform-tools/adb tcpip 5555 Library/Android/sdk/platform-tools/adb connect YOURDEVICEIP:5555
- รอดูผลของการเชื่อมต่อ
- ถอดสาย USB ออก แล้วก็ debug ผ่าน WIFI โลด
ที่มา
Apache Tuning from How To Optimize Apache
Timeout 300 KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 15 MinSpareServers 5 MaxSpareServers 10 StartServers 5 MaxClients 150 MaxRequestsPerChild 0
Create new user how
sudo adduser userName
Make user sudo how
sudo adduser userName sudo
MySQL Configuration
- Increrase memory size for MySQL Server using nano /etc/my.cnf and add/change value ตามรายละเอียด
innodbbufferpoolsize = 2048M innodblogfilesize = 512M maxconnections = 500 keybuffer_size = 512M
PHP Config
Set timezone to Asia/Bangkok
nano /etc/php/7.4/apache2/php.ini
date.timezone = Asia/Bangkok
Add CNAME domain.com to ppi.psu.ac.th
Add new site to Apache
cd /etc/apache2/sites-available nano sites-available/doname.com.conf
<VirtualHost *:80> ServerName domain.com ServerAdmin webmaster@localhost DocumentRoot /var/www/html/domain.com </VirtualHost> <VirtualHost *:80> ServerName www.domain.com ServerAdmin webmaster@localhost DocumentRoot /var/www/html/domain.com </VirtualHost> <IfModule mod_ssl.c> <VirtualHost _default_:443> ServerName domain.com ServerAdmin webmaster@localhost DocumentRoot /home/user/domains/domain.com </VirtualHost> <VirtualHost _default_:443> ServerName www.domain.com ServerAdmin webmaster@localhost DocumentRoot /home/user/domains/domain.com </VirtualHost> </IfModule>
cd /etc/apache2/sites-enabled ln -s ../sites-available/domain.com.conf domain.com.conf
Restart Apache
systemctl restart apache2
Restart MySql
systemctl restart mysql
INSTALL Let's Encrypt
1. ติดตั้งด้วย snap ดูรายละเอียดได้ที่ Certbot instructions
snap install --classic certbot ln -s /snap/bin/certbot /usr/bin/certbot certbot --apache certbot certonly --apache certbot renew --dry-run
2. ติดตั้งด้วย apt-get จาก repo
apt-add-repository -r ppa:certbot/certbot
After that, the following commands do not generate any errors:
apt update apt-get update apt install python3-certbot-apache
certbot --apache -d domain.com -d www.domain.com
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=domain.com
IMPORTANT NOTES:
Congratulations! Your certificate and chain have been saved at:
- /etc/letsencrypt/live/domain.com/fullchain.pem
- Your key file has been saved at:
- /etc/letsencrypt/live/domain.com/privkey.pem
- Your cert will expire on 2021-01-08. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew all of your certificates, run "certbot renew"
To test the renewal process, you can do a dry run with certbot:
sudo certbot renew --dry-run
Correct way to completely remove issued certificate(s) for a domain
certbot delete --cert-name domain.com
Copy file from another server using SSH
Alternatively, you could mount the myserver's filesystem over SSH with sshfs. This may be too much hassle for a one-off need, but convenient if you do this sort of thing often.
mkdir myserver sshfs -p 22 domain.com:/path/ myserver wget -O ~/myserver/path/to/remote/destination http://www.example.com/whatever rsync -trv myserver/src/path/ dest/path/ umount myserver
rsync in background
nohup rsync -trv myserver/src/path/ dest/path/ &
Dump Database
mysqldump -u [username] -p [database-you-want-to-dump] > [path-to-place-data-dump.sql] /usr/local/mysql/bin/mysqldump -u [username] -p [database-you-want-to-dump] > [path-to-place-data-dump.sql]
Ways to Flush DNS Cache on Mac OSx
sudo killall -HUP mDNSResponder
WhoIs LookUp
nslookup -type=ns softganz.com
Setup Time Sync
ติดตั้ง
apt-get install ntp
แก้ไข config
nano /etc/ntp.conf
เปลี่ยน server เป็น
server 1.th.pool.ntp.org server 0.asia.pool.ntp.org server 2.asia.pool.ntp.org server clock.nectec.or.th
Restart
service ntpd restart
หรือ
service ntp restart
ที่มา
- Certbot instructions
- How To Secure Apache with Let's Encrypt on Ubuntu 18.04
- E: The repository 'http://ppa.launchpad.net/certbot/certbot/ubuntu focal Release' does not have a Release file
- How To Use SSHFS to Mount Remote File Systems Over SSH
- How to wget a file to a remote machine over SSH?
- Correct way to completely remove issued certificate(s) for a domain
- How to increase memory size for MySQL Server
- MySQL Performance Tuning Settings
- HOWTO: Sync เวลาไม่ควรใช้ ntpdate ควรใช้ ntpd แทน