2023年3月15日 星期三

Flutter 開發筆記 - 撰寫平台相依性功能,以取得 Android Device 資料為例


研究了一下 Flutter 如何寫平台相依性的程式碼,看一眼也是常見的 Channel or Message 等溝通機制,也滿直觀的。以 Android 平台和 Kotlin 為例,先找到 MainActivity.kt ,接著,在 Code -> Override Methods 可以找到 configureFlutterEngine 可以添加

class MainActivity: FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
    }
}

接著就可以在透過 MethodChannel 建立綁定溝通管道:

import android.os.Build
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
    private val myCHANNEL = "samples.flutter.dev/helper"
    
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, myCHANNEL).setMethodCallHandler {
                call, result ->
            // This method is invoked on the main thread.
            // TODO

            if (call.method == "getBatteryLevel") {
                val batteryLevel = 0; // getBatteryLevel()
                if (batteryLevel != -1) {
                    result.success(batteryLevel)
                } else {
                    result.error("UNAVAILABLE", "Battery level not available.", null)
                }
            } else if (call.method == "getDeviceInfo") {
                result.success(getDeviceInfo())
            } else {
                result.notImplemented()
            }
        }
    }

    private fun getDeviceInfo(): HashMap<String, String> {
        val deviceInfo:HashMap<String, String> = HashMap<String, String>()
        deviceInfo.run {
            put("MODEL", Build.MODEL)
            put("MANUFACTURER", Build.MANUFACTURER)
        }
        return deviceInfo
    }
}

如此在 Flutter Dart 端,就可以呼叫:

class _MyHomePageState extends State<MyHomePage> {
  static const platform = MethodChannel('samples.flutter.dev/helper');

  String _deviceInfo = "system info unknown";
  Future<void> _getDeviceInfo() async {
    Map<String, String> deviceInfo = {};
    try {
      final Map<Object?, Object?> result = await platform.invokeMethod('getDeviceInfo');
      deviceInfo.clear();
      result.forEach((key, value) {
        if (key.runtimeType == String && value.runtimeType == String) {
          deviceInfo[key.toString()] = value.toString();
        }
      });
    } on PlatformException catch (e) {
      deviceInfo.clear();
    } on Exception catch (e) {
      //print("Exception catch: $e ");
    }

    setState(() {
      _deviceInfo = json.encode(deviceInfo);
    });
  }
...

後續就只是完善細節,強烈建議直接觀看官方文件,有完整的細流程資訊和各平台的範例: docs.flutter.dev/development/platform-integration/platform-channels 

Flutter 開發筆記 - 排除 Could not open settings generic class cache for settings file @ macOS 13.2.1, openjdk 19.0.2, Android Studio Electric Eel | 2022.1.1 Patch 2


最近工作上關係,來回顧一下 Flutter app 的開發,預計寫一款非常簡單的 App 試試水溫。結果在 macOS 13.2.1, openjdk 19.0.2, Android Studio Electric Eel | 2022.1.1 Patch 2 環境,預設弄個專案出來卻不能編譯:

Launching lib/main.dart on sdk gphone64 arm64 in debug mode...
Running Gradle task 'assembleDebug'...

FAILURE: Build failed with an exception.

* What went wrong:
Could not open settings generic class cache for settings file '/Users/UserID/AndroidStudio/usb_displayport_helper/android/settings.gradle' (/Users/UserID/.gradle/caches/7.5/scripts/XXXXXX).
> BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_' Unsupported class file major version 63

* 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 24s
Exception: Gradle task assembleDebug failed with exit code 1

研究了一下,主因是 JDK 與 Gradle 版本問題,需要多做一些事就能排除了。記錄一下。

此時環境:

% java --version
openjdk 19.0.2 2023-01-17
OpenJDK Runtime Environment (build 19.0.2+7-44)
OpenJDK 64-Bit Server VM (build 19.0.2+7-44, mixed mode, sharing)

這時,在既有專案的左邊上方的 Project 小視窗,挑選 android 目錄,點選右鍵 -> Flutter -> Open Android module in Android Studio -> New Window ,在新的 Android Studio 還沒按 Build 就看到訊息:

Unsupported Java. 
Your build is currently configured to use Java 19.0.2 and Gradle 7.5.

Possible solution:
 - Open Gradle wrapper settings, change `distributionUrl` property to use compatible Gradle version and reload the project

這時就來更換預設的環境: File -> Project Structure -> Project

- Android Gradle Plugin Version: 7.4.2
- Gradle Version: 7.6.1

按下 OK 就會開始抓資料,最後也順利編譯後在模擬器上跑了。

2023年1月31日 星期二

[Linux] lftp Fatal error: Certificate verification @ Synology NAS

從舊機搬遷資料出來時,除了 rsync 可用之外,還有 lftp 可以試試。結果一連就踩到 Fatal error: Certificate verification 問題,所幸有設定可以排除,後續就可以靠 lftp mirror 試試

$ lftp ftp://user@my-nas-ip
lftp user@my-nas-ip:~> ls                  
ls: Fatal error: Certificate verification: unable to get local issuer certificate (##:##)

解法:

$ lftp ftp://user@my-nas-ip -e "set ssl:verify-certificate false"

此外,若 Synology NAS 機型不會太舊,搬遷方式可以多試試 Migration Assistant 服務。

[Linux] cross compile tmux for Synology DS723+ via DSM 7.1 ToolChain - AMD x86 Linux 4.4.180 (r1000)

終於想不開把家裡的 NAS 升級了,一口氣跳到 AMD Ryzen R1600 型號,接著又要找一下編譯 tmux 的方法 Orz 參考六七年前寫的這篇:[Linux] cross compile tmux for Synology DS216play via DSM 6.1 Tool Chains - STMicroelectronics Monaco Linux 3.10.102 @ Ubuntu 16.04 64bit

過程:
原本找了一台小機器 Ubuntu 18.04 編譯,結果一直出錯,最後還是找個乾淨的機器,一下就搞定。這次用 libevent-2.1.12-stable 時,先略過 openssl 編譯 ,雖然編 openssl 也沒那麼難,但就是這麼懶 XD

Docker 流水帳:

% docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
10175de2f0c4: Pull complete 
Digest: sha256:9dc05cf19a5745c33b9327dba850480dae80310972dea9b05052162e7c7f2763
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
% docker run -it --platform linux/amd64 -p 10022:22 -p 18000:8000 ubuntu:22.04  
# apt update && apt upgrade -y && apt install -y lsb-release net-tools
# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
Codename: jammy

# apt install -y gcc g++ make python3 tmux vim git wget xz-utils file

開工:

# cd ~/
# wget https://global.download.synology.com/download/ToolChain/toolchain/7.1-42661/AMD%20x86%20Linux%204.4.180%20%28r1000%29/r1000-gcc850_glibc226_x86_64-GPL.txz
# tar -xvf r1000-gcc850_glibc226_x86_64-GPL.txz

# cd ~/
# wget https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.4.tar.gz
# tar -xvf ncurses-6.4.tar.gz
# cd ncurses-6.4
~/ncurses-6.4# PATH=$HOME/x86_64-pc-linux-gnu/bin:$PATH CC=x86_64-pc-linux-gnu-gcc CFLAGS="-I$HOME/x86_64-pc-lix-gnu/include" ./configure --build x86_64-pc-linux-gnu --prefix=$HOME/x86_64-pc-linux-gnu/
~/ncurses-6.4# PATH=$HOME/x86_64-pc-linux-gnu/bin:$PATH make -j2 install

# cd ~/
# wget https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
# tar -xvf libevent-2.1.12-stable.tar.gz
# cd libevent-2.1.12-stable
~/libevent-2.1.12-stable# PATH=$HOME/x86_64-pc-linux-gnu/bin:$PATH CC=x86_64-pc-linux-gnu-gcc CFLAGS="-I$HOME/x86_64-pc-lix-gnu/include" ./configure --build x86_64-pc-linux-gnu --prefix=$HOME/x86_64-pc-linux-gnu/ --disable-openssl
~/libevent-2.1.12-stable# PATH=$HOME/x86_64-pc-linux-gnu/bin:$PATH make -j2 install

# cd ~/
# wget https://github.com/tmux/tmux/releases/download/3.3a/tmux-3.3a.tar.gz
# tar -xvf tmux-3.3a.tar.gz 
# cd tmux-3.3a
~/tmux-3.3a# PATH=$HOME/x86_64-pc-linux-gnu/bin:$PATH CC=x86_64-pc-linux-gnu-gcc CFLAGS="-I$HOME/x86_64-pc-linux-gnu/include -I$HOME/x86_64-pc-linux-gnu/include/ncurses" LDFLAGS="-L$HOME/x86_64-pc-linux-gnu/lib" ./configure --build x86_64-pc-linux-gnu --prefix=$HOME/x86_64-pc-linux-gnu/ --enable-static
~/tmux-3.3a# PATH=$HOME/x86_64-pc-linux-gnu/bin:$PATH make -j2
...
x86_64-pc-linux-gnu-gcc -std=gnu99 -O2    -I/root/x86_64-pc-linux-gnu/include -I/root/x86_64-pc-linux-gnu/include/ncurses -static  -L/root/x86_64-pc-linux-gnu/lib -o tmux alerts.o arguments.o attributes.o cfg.o client.o cmd-attach-session.o cmd-bind-key.o cmd-break-pane.o cmd-capture-pane.o cmd-choose-tree.o cmd-command-prompt.o cmd-confirm-before.o cmd-copy-mode.o cmd-detach-client.o cmd-display-menu.o cmd-display-message.o cmd-display-panes.o cmd-find-window.o cmd-find.o cmd-if-shell.o cmd-join-pane.o cmd-kill-pane.o cmd-kill-server.o cmd-kill-session.o cmd-kill-window.o cmd-list-buffers.o cmd-list-clients.o cmd-list-keys.o cmd-list-panes.o cmd-list-sessions.o cmd-list-windows.o cmd-load-buffer.o cmd-lock-server.o cmd-move-window.o cmd-new-session.o cmd-new-window.o cmd-parse.o cmd-paste-buffer.o cmd-pipe-pane.o cmd-queue.o cmd-refresh-client.o cmd-rename-session.o cmd-rename-window.o cmd-resize-pane.o cmd-resize-window.o cmd-respawn-pane.o cmd-respawn-window.o cmd-rotate-window.o cmd-run-shell.o cmd-save-buffer.o cmd-select-layout.o cmd-select-pane.o cmd-select-window.o cmd-send-keys.o cmd-server-access.o cmd-set-buffer.o cmd-set-environment.o cmd-set-option.o cmd-show-environment.o cmd-show-messages.o cmd-show-options.o cmd-show-prompt-history.o cmd-source-file.o cmd-split-window.o cmd-swap-pane.o cmd-swap-window.o cmd-switch-client.o cmd-unbind-key.o cmd-wait-for.o cmd.o colour.o control-notify.o control.o environ.o file.o format.o format-draw.o grid-reader.o grid-view.o grid.o input-keys.o input.o job.o key-bindings.o key-string.o layout-custom.o layout-set.o layout.o log.o menu.o mode-tree.o names.o notify.o options-table.o options.o paste.o popup.o proc.o regsub.o resize.o screen-redraw.o screen-write.o screen.o server-acl.o server-client.o server-fn.o server.o session.o spawn.o status.o style.o tmux.o tty-acs.o tty-features.o tty-keys.o tty-term.o tty.o utf8.o window-buffer.o window-client.o window-clock.o window-copy.o window-customize.o window-tree.o window.o xmalloc.o osdep-linux.o    compat/closefrom.o compat/fgetln.o compat/freezero.o compat/getdtablecount.o compat/getpeereid.o compat/getprogname.o compat/setproctitle.o compat/strlcat.o compat/strlcpy.o compat/strtonum.o compat/recallocarray.o compat/getopt.o compat/imsg.o compat/imsg-buffer.o compat/vis.o compat/unvis.o compat/fdforkpty.o -lutil -lncurses -levent_core -lm  -lncurses -lresolv
cmd-parse.o: In function `yylex_token_tilde':
cmd-parse.c:(.text+0x61d): warning: Using 'getpwnam' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
cmd-parse.c:(.text+0x6a9): warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/root/x86_64-pc-linux-gnu/lib/libevent_core.a(evutil.o): In function `test_for_getaddrinfo_hacks':
evutil.c:(.text+0x1836): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/root/x86_64-pc-linux-gnu/lib/libevent_core.a(evutil.o): In function `evutil_unparse_protoname':
evutil.c:(.text+0x1272): warning: Using 'getprotobynumber' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/root/x86_64-pc-linux-gnu/lib/libevent_core.a(evutil.o): In function `evutil_parse_servname':
evutil.c:(.text+0x11ee): warning: Using 'getservbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

~/tmux-3.3a# file tmux
tmux: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, with debug_info, not stripped

~/tmux-3.3a# python3 -m http.server 
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

還記得當初跑 docker 時有把本機的 18000 port 對到裡頭的 8000 port ,這時就可以靠 http://localhost:18000/tmux 去下載 tmux 來用。

實際運行:

$ uname -a
Linux NAS 4.4.180+ #42962 SMP Thu Dec 8 21:34:11 CST 2022 x86_64 GNU/Linux synology_r1000_723+

$ ~/bin/tmux -V
tmux-tool 3.3a

另外,在 NAS 內運行時,可以多設定 shell 環境資訊:

$ cat ~/.profile 
export PATH=$HOME/bin:$PATH
export TERM=xterm

收工!

2023年1月23日 星期一

安裝 PC 版 app 舊版 Line v6.7.3.2506 @ macOS 10.13.6

之前在 Macbook Pro 13-inch, Late 2011 在 2020年重灌後,一直靠 Chrome Browser extension 用 Line 服務 (Ver 2.5.8 @ 2022/12/22 更新),今年回鄉使用時,發現很多 app icon 縮圖也怪了,開始想裝舊版 PC app 了 XD 可惜 macOS App Store 的最新架上版本已經不能裝了,要求 macOS 版本不合。

找了一下,有些論壇都在提供舊版 dmg (或 App 壓縮檔案),瞬間才想起 macOS App Store 可以去找以前下載過的版本,瞬間可以解決需求 XD 且又不用擔心網路來源不明的程式。安裝到 Line v6.7.3.2506 版本,收工!

缺點就是佔了個 100MB 系統空間。