Flutter 二三事

這兩天試驗 flutter 時,查找到的一些東西,大致上還蠻順利的。

安裝 flutter

照官方文件 (Linux install) 來進行安裝,大致沒什麼問題。

我碰到的問題是,執行 flutter doctor 以後有 Android license status unknown. 的問題。可是 Android SDK 也裝了,應該是要可以才對。

後來自行去執行 Android SDK 裡的 sdkmanager 以後,才知道是因為無法執行 sdkmanager 而導致 flutter doctor 檢查失敗。我檢查了一下 java 的版本,目前使用的是 java 11,而 Android 還不支援 java 11,所以改安裝 openjdk-8-jdk 以後,再執行 flutter doctor –android-licenses 就可以了。

RenderFlex overflowed

這個是因為 Layout 固定 (StackOverflow),鍵盤出現,會蓋住輸入框,flutter 很貼心的出現這個 warning ,提醒要改用可以 Scroll 的 View我是改用 SingleChildScrollView:https://api.flutter.dev/flutter/widgets/SingleChildScrollView-class.html

退出 app

有查到這個退出 app ,說可以用 exit(0),也可以用

import 'package:flutter/services.dart';
// ...
SystemChannels.platform.invokeMethod('SystemNavigator.pop');

但有人說 SystemNavigator.pop 只適用於 Android。

講 Layout 的

其他

編譯 Android 裡能用的 tcpdump

已經有人提供腳本了:chatch/tcpdump-android: Build tcpdump for Android

很方便,照著 README 做就可以,自己試了以後,發現需要對 build-tcpdump 腳本做些調整,要不然會失敗,先用熟悉的編輯器開啟 build-tcpdump,然後:

  1. 找到 make-standalone-toolchain.sh ,加入 –force 。不加的話,會因為事先建了 toolchain 而警告。
  2. 找到 CFLAGS,在雙引號裏面加入 -D__ANDROID_API__=$android_api 。不加的話,會因為 checking for pcap_loop… no 而停止 tcpdump 的 configure。

然後再執行 ./build-tcpdump 就可以囉。

如果有任何問題想重來什麼的,砍掉 tcpdumpbuild 這資料夾就可以了。

參考資料:

SugarORM

因為想偷懶,之前有看到 Sugar ORM,感覺上很簡單易用,就試試看了。大致上照網頁上的說明,就可以用了,這裡主要提一些比較不清楚的地方。

  1. 使用 Android Studio 的話,compile ‘com.github.satyan:sugar:1.3’ 這行是放在 app/build.gradle 裡的 dependencies {} 裡。
  2. 放在 AndroidManifest.xml 裡的 meta tag 很重要。DOMAIN_PACKAGE_NAME 要跟你 entity class 的 package name 對應到,否則,會沒辦法自動建立資料表格。VERSION 在第一次開發時,是隨便給,但在之後有變動 entity class 以後,要出更新版本時,這裡要記得累加。如果都還沒上架,那倒是沒關係,可先都不變,碰到問題時,先 uninstall 再 install app 就可以了。
  3. 在 app 啟動時,查看 Logcat ,可以看到 SugarORM 輸出的訊息,說建立了什麼資料表格,如果使用上有問題,不妨看看,會有所幫助。
  4. 不支援 1 對多、多對多的關係。1 對多,可以在類別裡建立欄位跟函式來處理:

    至於多對多,也是可以用傳統 RDB 的觀念來炮製。

官方網頁裡還有提到直接 Query 跟 Migration,這邊我就沒試了。

MonkeyRunner easy module

前一陣子又在折騰 MonkeyRunner,意外發現有 easy 這個 module,順道研究了一下 ViewClient 。

easy 這個 module 是內建的,功用有點類似 jQuery,可以幫你直接找到目前畫面的某個元件,這樣就可以快速的在裏面填入文字或是按下按鈕等等。

這例子會啟動 Email ,然後將資料填入欄位後,寄出去。但實際上並不會寄出,而是存到草稿 (Draft) 裡,這是由於 Email 在寄送郵件的程式裡,有去判斷,假若是透過 MonkeyRunner 所觸發的事件,他就不寄送,而是存到草稿裡。

easy module 還有提供一些方便的函式,主要都是操作 UI 用的比較多。假若你有下載 Android 原始碼的話,這部份是在 sdk/monkeyrunner/src/com/android/monkeyrunner/easy 資料夾下面。

ViewClient 則是有人覺得不夠用,就另外自己開發了。一開始是配合 MonkeyRunner 才能使用,到了 3.0 以後,就可以不需要 MonkeyRunner,用 Python 搭配 Android SDK 就可以使用。 話是這麼說,但實際上,還是得視手機 Android 版本而定,總之使用 ViewClient 有看到錯誤訊息,就試著改用 2.3.25 的版本試試看吧。下面就是大致的用法:

ViewClient 在找元件的部份,有點亂,網站上文件也不太清楚,我追蹤原始碼,是一定要 dump ,才能找到。而且,沒辦法用 id 來找,只能用文字來找。看原始碼還有提到 UI Automator 這工具,但後來就沒詳究了。我後來沒有用 ViewClient ,所以…

 

小技巧,在找畫面上有哪些元件時,可以用 hierarchyviewer/hierarchyviewer1 這工具來看畫面佈局,這相當好用。

參考資料:

MMS 與 SMIL 小記

SMIL 是 MMS 在使用的格式,其實就是類似 HTML/XML 的文字檔案,還蠻容易了解的,比較詳細的介紹可以參考這篇文章:SMIL Guide

  • 在 Android 裡,可以把下列的檔案複製出來,然後用 sqlite3 打開,輸入 select * from part; 就可以看到
    • /data/data/com.android.providers.telephony/databases/mmssms.db
    • /data/data/com.android.providers.telephony/databases/mmssms.db-journal
  • 基本上只要在簡訊裡附加圖片並輸入文字,也就是 MMS ,就可能會使用到 SMIL 。
  • SMIL 的 layout 放在 head tag 裡,也就是說,假若有多個 slide,都會是同一個 layout,因為一份 SMIL 文件只會有一個 head tag。而 body tag 裡的 par tag 代表一張 slide,這裡可以利用 dur attribute 指定播放的時間。slide 可能不只一張,所以可以有多個 par tag。
  • 電信營運商 (Carrier)  的不同有可能會導致送出的 SMIL 與收到的 SMIL 不一樣,目前我有遇到的情況是,營運商是遠傳,送出文字在上、圖片在下的 Slide 以後,收到會是圖片在上、文字在下的 Slide;中華電信的話,就沒問題。
  • 傳送 3gp 的影片,傳送以後,收到時會是一個 GIF 圖片以及一個 AMR 音效檔,Android 並沒有做轉換的工作,轉換是在運營商那邊完成的。

Log 與 Slog

在設定裡USB debugging 被關閉的情況下,Log 並沒有真正的輸出到 logcat。這種情況下就要使用 Slog,這樣子即使沒有 USB debugging 也會輸出到 logcat,但這時候要注意另外一點,因為 logcat 的緩衝區是有限制的,如果輸出過多,之前的訊息就會被刷掉。

執行指定的 CTS 項目

首先在 mydroid 目錄下要有 buildspec.mk,在編譯之後,再使用 make cts 就可以編譯完成。

使用的時候就執行 mydroid/out/host/linux-x86/cts/android-cts/tools/cts-tradefed ,接著就會出現 cts-tf > 的提示字元。這裡可以使用 help 查看可以使用的指令,要執行單一項目就是使用  run cts -c android.telephony.cts.TelephonyManagerTest -m testGetDeviceId 即可。

Android 與網路攝影機(2)

在可以播放以後,會想到的是能不能順便錄影?

Android 上的錄影在網路上可以找到的範例,多半是用既有的 MediaRecorder (Android 應用程式開發:如何錄製影片) 或是發 Intent 給可以錄影的 app (Recording Videos Simply) 來做。由於之前選用的是 Motion JPEG,這兩個方法都不可行。MediaCodec 似乎可用,但沒認真去找範例。

延續前篇,看了 MjpegView 原始碼,裏面的 MjpegViewThread 是使用 MjpegInputStream 在讀取 Motion JPEG,讀到一張圖,就畫在 SurfaceView 上。在 StackOverflow 上有看到 jcodec,可以餵給他 bitmap ,然後會壓縮出 H.264 影片。這正好是我所需要的,就拿來試試看了。

套用以後的結果放在 github 上,這裡就不貼程式碼了。實際上,jcodec 是合用,而且有特別針對 Android 提供一些方便的 Helper function,但是還是有缺點,第一個文件不是很齊全,StackOverflow 上能找到的 jcodec 範例或多或少都有點問題,建議是去下載最新的版本,然後參考裏面的 example 來使用;第二個是編碼後的影片不是每個裝置都能播放,電腦上播放倒是沒問題。第二個問題還蠻大的,關於這點,有人回報給 jcodec 的 issue tracker 了:Generate MP4 viewable on all versions of Android? · Issue #25 · jcodec/jcodec

後來沒繼續再深究下去,僅針對曾經有看過的部份做個筆記,就這樣。

Android 與網路攝影機(1)

大部份網路攝影機都會提供多種格式,例如 AVI、Motion JPEG 等等,這邊我選擇的是 Motion JPEG,主要原因是 Android 有直接支援這種格式 ,不會牽涉到「可能沒有解碼器」的問題。

首先是環境的準備,因為手頭沒有一般市售的網路攝影機,只好搭配手頭上有的 USB Cam ,克難的自己弄一個。 很幸運,正好有人用 python + OpenCV 寫了一個簡單的 Streaming Server,輸出格式正好就是 Motion JPEG ,網址是 https://gist.github.com/n3wtron/4624820

然後播放的部份,我是參考 StackOverflow 上的這篇 Android and MJPEG – Stack Overflow ,程式主要是繼承 SurfaceView 做出 MjpegView 來使用,MjpegView 裡則使用 thread 搭配 MjpegInputStream 去讀取指定位址的 Motion JPEG,進行播放。但這個程式有一個小問題,在 Android 3.0 以後,以 HttpClient (MjpegInputStream 裡使用了 HttpClient )去讀取網路資源時,會丟出 NetworkOnMainThreadException 。因此需要對程式進行改寫。

很幸運,StackOverflow 又有人提出解:Android ICS and MJPEG using AsyncTask – Stack Overflow 。這樣拼拼湊湊之下,要播放網路攝影機上的影像不是難事。

P.S. StackOverflow 上的範例程式有個問題,就是沒妥善處理 onPause/onResume,因此在按 Home 或切到別的程式再回來時,會沒辦法繼續播放。

[Android]用 am 輸入 MMI code

在 Android 裡,用 am 撥號,可以這樣用:am start -a android.intent.action.CALL -d tel:09xxxxxxxx

在撥號畫面裡,使用 MMI code 可以帶出一些特殊的畫面,每隻手機都不太一樣,但一般來說都會有 # 這些特殊字元,因此 -d tel:*#38# 這樣的參數就會失效。am 的原始碼在 frameworks/base/cmds/am 下,這邊可以看到 am 會用 Uri.parse 去解析 -d 後的參數,問題就出在這裡。因為是以 Uri 處理,因此也需要遵循 Uri 的規則,# 應該要使用 %23 才行。

所以使用 am start -a android.intent.action.CALL -d tel:*%2338%23 就可以成功。

小技巧是,你可以在編譯後,執行 out/host/linux-x86/bin/monkeyrunner ,在裡面依序輸入,就可以取得編碼後的 Uri 字串:

[python]
from android.net import Uri
print Uri.encode(‘your_string’)
[/python]