宛如一位 commit 風格師

Image for post
Image for post
No

最近工作上學到一些整理 git commit 的技巧,大部分圍繞在 git rebase 的功能使用。透過這些方法整理出易懂的程式開發過程,也方便 code review 的人或是未來的自己了解這一段時間的所作所為。

有鑑於每個人或團隊適合消化的 commit 數量不同,必須跟著需求調整。最常見的整理不外呼是:將一個過大的 commit 切細、將過多細小的 commit 合併為一個。
本篇主要以 CLI 操作為準,全部的行為都會以命令列為主。在這裡以一個簡化的專案作為範例,操作流程可以套用至各個專案,應該是大同小異。

警告:修改歷史可能會造成 conflict,請小心為上。

本範例 repository 線圖如下:

Image for post
Image for post
這個範例有 5 個 commit

切分 commit

TL;DR

1. git rebase <hash>~ -i
2. 將需要拆分的 commit 設為 edit
3. 因 rebase 在過程途中,git 會停在該節點等待你編輯
4. git reset HEAD~
5. 對 Code 做任何調整,add 變更後 commit。
這一階段沒有限制 commit 的數量
6. 最後 git rebase --continue

取得 commit 的 hash 字串

本例以範例程式碼的 commit 為例,將它拆分細部程式碼。
你可以透過 git log 指令取得每個 commit 的 hash 字串,如果你想要像範例圖片的 git log 表現方式,可以使用下列的指令:

$ git log --oneline --graph
Image for post
Image for post
你可以想像每個 Hash 都是該 commit 的 id

複製 commit 的 Hash 字串,如果你使用 git log,則複製標題 commit 旁邊的 Hash (會比較長)。
接下來鍵入下列指令,進行 rebase,別忘了 Hash 後面加上「~」。

$ git rebase <hash>~ -i

git rebase 修改歷史

使用這個指令,會進入 rebase interactive mode 。進入該模式後,將需要拆分的 commit 設為…


如何順眼的呈現程式碼增添幸福感

Image for post
Image for post
Relax and chill

在眾多資料整理的解決方案中,Google 文件是當中很受歡迎的選項。
除了近似於 Word 的編輯界面,文件處理功能也很豐富強大。
資訊相關從業人員在整理文件時,有時會需要當程式碼附在其中,無奈的是 Google 文件沒有做相關調整,實在稱不上適合顯示程式碼的平台。

最近我也遇到類似的狀況,研究了一番後,發現可以透過幾個簡單技巧改善 Google 文件的程式碼顯示,主要分為兩個部份:

  1. 使用外掛程式改善語法高亮及排版
  2. 改用更適合程式碼顯示的字體

使用 Code Blocks 外掛程式

安裝外掛程式

從 Google 文件的功能選擇「外掛程式」 ->「取得外掛程式」

Image for post
Image for post

跳出外掛程式視窗後,在搜尋欄搜尋「Code Blocks」

Image for post
Image for post

安裝由 Alex Forsythe 製作的 Code Blocks 外掛程式

Image for post
Image for post

使用 Code Blocks

在文件裡,貼上或手打程式程式碼

Image for post
Image for post

選取程式碼,選擇上方工具列 -> Code Blocks -> Start
會跳出 Code Blocks 功能的側邊欄

Image for post
Image for post

選擇自己喜愛的 Syntax highlighting 後按下 Format,讓 Code Blocks 幫你做美化工作。本外掛程式不用特定選擇某一個程式語言, 它提供 auto 「自動辨識」功能。

Image for post
Image for post

由結果可以發現,比起單純改成等寬字體,用 Code Blocks 呈現過的程式碼在閱讀感受方面更上一層樓。

改用更適合的字體

Google 文件裡頭常用拿來顯示程式碼的字體是 Courier New、Consolas,但我們其實可新增更多的字體,例如 Fira CodeSource Code Pro

從字體選單,選擇「更多字體」

Image for post
Image for post

從顯示選單裡頭,顯示:所有字體 -> 等寬

Image for post
Image for post

本例以 Fira Code 為例,直接選擇即可

Image for post
Image for post

新增字體後,就能直接在字體選單裡頭選擇到剛剛新增的字體。
另外,Google 文件可以顯示 Font ligatures (連字功能,可以參考 Fira Code 說明頁面),如果選擇支援 Font ligatures 的字體,也能呈現。

Image for post
Image for post


直接擁有一個昨天就應該內建在 IDE 裡頭的功能

Image for post
Image for post
「OMG 好快⋯⋯ 已經進入下班模式?」

在 Android 專案處理多國語系只要遵循 strings.xml 語言設定,基本上都能快速無痛的搭建起來。 Android Studio 在 2.X 時期新增了 Translations Editor,方便開發者在一個分頁之中,全攬所有的語言設定,處理起多語言更加地有效率。
Translations Editor 提供一個類似於試算表軟體的介面,編輯特定文句的翻譯很方便。但不適合團隊中非開發人員使用,畢竟請非開發人員安裝 Android Studio 再怎麼說也怪怪的。最近公司專案就遇到類似的問題,為了加入更多的語言,需要與更多翻譯人員合作開發專案。

Image for post
Image for post
Translations Editor 省下開發人員許多心力

當下第一個念頭是將語言檔案製作成試算表,做成共同編輯文件。
在網路上找解決方案一段時間,發現大部分的作法都已經失效 ,只剩下在 Translations Editor 之中按 Ctrl + C 複製後貼到試算表上。在 800 多行的 xml 檔案之中做手工藝活,恐怕會影響身心。

自動化轉換

android-lang-tool 就是為了解決問題而出現的—— 自動將每個語言的 strings.xml 設定整合並產生試算表檔案的工具。
在使用之前,請先確認你的電腦已經安裝了 Java。☕️

興高采烈地進去 GitHub Repo 發現,要自己編譯⋯⋯
快別管那麼多了,我編譯好了,點擊這裡下載。🚀

  1. 先將下載的(或你編譯的) 放置於 Android 專案的目錄
  2. 開啟終端機 (Terminal),切換至該專案目錄
  3. 下指令 (讓他可以存取到專案的 資料夾)
$java -jar langtool.jar -e ./app/src/main
Image for post
Image for post
處理的過程中,android-lang-tool 會提醒沒有翻譯的 key

4. 會在相同目錄下產生一個 檔案

Image for post
Image for post
輸出結果 sample
Image for post
Image for post
缺少的翻譯會自動填上底色

結果看起來明確清晰,各個 Key 依照不同的翻譯一字排開。android-lang-tool 也會將翻譯字串之中缺少翻譯的 key 用紅色底色標記,而 plurals、array 等特殊的翻譯會留下註解。

自行編譯 lang-tool.jar

如果想要自行編譯 ,可以自行從 android-lang-tool repo clone 下專案。
編譯之前需要安裝 Maven,在 macOS 系統上可以透過 homebrew 安裝。

$brew install maven

Maven 安裝好後,接著切換至剛剛 clone 下來的 android-lang-tool 目錄。
輸入以下指令

$mvn package

如果編譯成功,編譯後的 jar 檔案會在

lang-tool/target/langtool-1.0-SNAPSHOT-jar-with-dependencies.jar

使用這個 jar 檔案,即可照著第一段的流程,輸出多國語言字串試算表。

疑難排解

Q. 編譯過程之中出現:source option 5 is no longer supported. use 7 or later. 並且編譯失敗該怎麼做?

A. 你目前用的 Java 版本太新了,試著降至 Java 8 再編譯一次。


現在可以在同一個專案之中,一次開啟多個不同的 branch 了。

Image for post
Image for post
標題說的是真的嗎?

近日在推特上看到這篇推文:

發現了很多以前不知道的 git 功能,這次引起我注意的除了 git rerere 以外,還有 git worktree 這個指令。我因為好奇研究了一番,發現這個指令可以適用於以下的情境:
在開發途中,時常需要切到其他 branch,無論是需要對照、修 bug 或是開發一個插單的新功能。類似這種情形,我常常會 目前的更動,待處理完其他事情回來再 (或是先 commit 變更,待其他的 Task 處理完回來後再 )。

git 2.5 之後新增了 ,就可以減少 branch 切來切去的各種麻煩。這裡的 worktree 指的是 Working Tree (工作目錄),其實,在某個資料夾裡進行 或是 clone 一個遠端的專案下來,這個資料夾就會變成一個工作目錄。(即是由 git 管理的專案資料夾)
這個指令可以為同一個專案製造多個工作目錄,並且其他目錄的變更經 commit 後,會回到原工作目錄。

遇到需要警急上 patch 修 bug,但又不想 掉目前的開發進度。現在可以新增新的工作目錄另外處理,不影響到目前的開發狀況。

範例

以我手邊的 Android Codelab 教學專案為例,現在的狀況是我更動到一半:

Image for post
Image for post

現在需要回 master branch 改東西,想像成是修 bug 打 patch 之類的。
在說明 指令之前,我先補充說明我的幾個習慣作法:

  1. (1) 先 後回到 master branch
    (2) 在 master branch 開一個新的 branch
    (3) 這個 branch 處理完之後回到原 branch
    (4) 考慮到可能在其他地方也做了 所以用 來查是哪一個 stash 是上次離開前的狀態
    (5) 記下 index ,下


都幾月了還這麼熱?

Image for post
Image for post
素每!!!!!!

target SDK Version migrate to Oreo(26)

Image for post
Image for post
圖片來源:Android Developer

沒想到 Play Store 也兇起來了,2018 年 8 月以後所有新的應用程式都必須 設定 targetSDK 至 26 版。既有程式則是於 11 月前需要完成 Migrate,否則就有可能無法更新。

targetSDK 版本會影響 App 在 Runtime 中的行為,例如以前將 targetSDK 設定在 23 (Marshmallow) 以下,就無需動態透過 Dialog 來獲取一些手機功能的權限 (例如讀取內部空間、存取相機⋯ 等),只要在 Play 商店下載程式後,就全部授與了。😅

Target 到 Oreo 之後,所有 Service 皆需要有明顯的 Notification 讓使用者知道有 Service 正在運行,否則在 5 秒內系統會停止這個 Service。更緊縮了一些系統廣播,避免了太多不必要的 Service 在背景執行的問題。

在有 Play 商店的宇宙,這是一個很大的進步。至於其他的平行宇宙,還是自求多福吧。

Android JetPack

Image for post
Image for post
圖片來源:Android Developer

Android Support Library 被棄用了,你沒看錯 Support Library is deprecated。它被改名成 Android X Library 與去年發表的 Android Architecture Component 做了整合,現在都成為 Android JetPack 的一員。

這麼做最大的好處是將 Support Library 與 Compile SDK 版本脫鉤,在 Android X Library 之前,升級 Support Library 時,也一併需要升級 Compile SDK 版本,所以 Support Library 版本號總是跟著 Compile SDK 版本走。
但在 Android X 與 Compile SDK 脫鉤後,升級的速度可以比以往更頻繁。更早享受新功能,更早修復問題。也免除了詭異的 Package Name,例如 v4 Support Library 最低支援版本早已不是 v4。Google 也在持續的解耦 Android X…


一個更好的 Deep Link for Android

Image for post
Image for post
No way!!!!

簡介

要實現跨 App 之間的跳轉,在 Android 上第一個想到的應該會是 Deep Link。Deep Link 是透過一組 Scheme,例如 ,在 AndroidManifest 註冊 Intent Filter,讓 Android 可以在處理 這個 Scheme 時,開啟註冊的 App。當然也可以處理 這兩個網址常用的 Scheme。

不過,每個人都能註冊同一個 Scheme,被惡意重複註冊 Scheme 而開啟了其他的 App 是可能發生的。就像是 這兩組,通常使用者點下去後,會出現很多 App 可以處理,使用者需要從裡頭選擇一個來處理。

Google 在 Android 6.0 (APIv23, Marshmallow) 釋出時,也提出了新的 Android App Links。就能解決上述提到的幾個問題,使用者不必再從可以處理的程式之中選擇由哪個程式處理,Android App Links 直接將使用者帶到目標的程式。 (當然,如果沒安裝目標 App 需要另外處理,但不在本文的討論範圍)
另外,要設定 Android App Links,可能需要和 Web front-end 合作一下。(雖然也能自己來)

設定

Image for post
Image for post

Android Studio 2.3 之後提供類似精靈介面(全名是 App Links Assistant),讓開發者可以簡單的設定 App Links。你可以從選單列的 Tools -> App Links Assistant 開啟,照著 Assistant 側邊欄中的四個步驟設定 (可以將第三個與 Web 配合的步驟調整成最後一個),應該就能簡單的設定完成 (如果要配置 Deep Link,走 1、2、4 也能達成)。

Image for post
Image for post

步驟一是在 Android Manifest 檔案裡頭加入 Intent Filter,例如電子書搜尋服務用來做 App Link 的位置是 ,Host 是 這段,後面取變數使用 這個 PathPrefix 來偵測(如果使用 PathPrefix 符號是必須的,別忘了),另外,需要指定用來開啟 App Links 的 Activity。
你可以在 Check URL Mapping 對話框內檢查 App Links…


利用螢幕密度資料夾,簡易的做判斷

Image for post
Image for post
「不只是解析度。」

當然是指 Android App 要怎麼判斷目前的環境是不是一台平板電腦。但話又說回來,說到 Android 平版,空氣中似乎有點參雜悲傷。最近專案需要為平板做雙欄(dual pane)介面,也需要對平板做一些特別的調整。
因為以上原因,做了一些調查。很遺憾,目前沒有確切的方法知道 App 的環境是不是一台平板,除非未來廠商有提供 API 查詢,否則現在只能透過螢幕或解析度的大小來推測。

在 Google I/O 2013 年的 Android 程式之中,Google 曾經用以下的方法來判斷是不是平板:

時過境遷,現在 (2018) 的 Android 旗艦手機已經往 6 吋邁進,連憋了很久的友商都出了 6 吋手機在大螢幕上見。為什麼一直提 6 這個夢幻的數字呢?原因是這上面的作法 6 吋以上就會被視為平板。
現在牽扯到「平板是什麼」這個哲學問題,為了避免無限的詢問,先把話題拉回來。我這裡先把 Google Nexus 7 當成判斷平板的基準,將 7 吋以上的機器視為平板 (什麼恐怖的就不要再提了)。

Android 習慣使用的長度單位不是 px (pixel),而是由像素密度換算過的 dp (density-independent pixels)。在 160dpi (aka. mdpi) 的手機上,1dp 會等於 1px。(你可以透過 Display Info 這個 App 知道自己的手機的像素密度 dpi),接下來依照個像素密度進行縮放調整。

0.75 倍 -> ldpi
1 倍 -> mdpi
1.5 倍 -> hdpi
2 倍 -> xhdpi
3 倍 -> xxhdpi
...

我們要用最小寬度 (smallest width) 來推測,目前是不是跑在平板電腦上。他是用 Portrait Mode 下 (直立裝置,這是預設條件),Activity Window 的寬度有沒有超過最小寬度 (smallest width) 來判別。

Image for post
Image for post
圖片來源: Android Developer 文件

所以在做平板 Layout 時,Android 的文件才會請開發者新增目錄專門放這類大螢幕的 Layout。

res/layout/main_activity.xml         # For handsets
res/layout-sw600dp/main_activity.xml …


留點提示給未來維護的人,降低翻車率

Image for post
Image for post
同一個 meme 用兩次

Android 專案裡頭的資源,無論是 String、Drawable 或是放在 Raw 裡頭的檔案,都會被 aapt 工具產生一個 id 作為對應,並存在 R Class 裡頭。例如開發者想存取字串資源,在 Java/Kotlin 程式碼之中透過 ,在 XML 之中透過 就可以取得該字串。
這些 id 的資料型態都是 Int,在一個 Method 傳入一個資源 id ,在該 Method 參數的部分即是需要傳入 Int,這類的 Method 通常需要注意未來使用的人 可能 誤用而傳入一般的整數。當然 Method Name 好好想應該可以避免這類的問題,真不愧是寫程式最大難題。

但除了好好想名字以外,Android Support Library (Android X) 提供了 Annotation Library。在程式碼之中存取了 Annotation 註釋過的變數,Android Studio 會跳出相關的提示,像是提醒這個變數需要 String 資源、這個資源不能為空⋯ 等等,你應該會在很多第三方 Library 之中發現他們都有引用這個 Library。

Image for post
Image for post

例如上方的範例,呼叫 時, 傳入 5566,IDE 就會跳出紅字提醒。

在開始以前,需要在 Gradle 之中加入新的 dependency (擇一):

dependencies {
// If you stay on Support Library
implementation 'com.android.support:support-annotations:28.0.0'
// If you use AndroidX
implementation 'androidx.annotation:annotation:1.0.1'
}

常用範例簡介

Nullable/NonNull

上次提到 Java 如何跟 Kotlin 更好的協作,有提到這兩個 Annotations。這兩個 Annotations 的功能是提示目前的變數有沒有可能是 null,可以與 Kotlin 的 Null safety 檢查功能互相配合。
就算只使用 Java 本身,編寫程式時也可以透過 IDE 的提示獲得提醒,也可以透過文件知道這個參數本身能不能傳 null…


摸索錯誤處理的 operators

Image for post
Image for post
「Observa……..ble!?????」

RxJava 是一套適合實作非同步處理的框架,最近幾年很多的開發者將網路請求由 AsyncTask 實作轉移至由 RxJava 包裝過的處理方式。一般使用上,常常只用來做最基本的網路非同步處理,也就是在 之後,在 處理成功,在 處理失敗。
每一次的 RxJava 訂閱,可以視為一個事件被發射。開發者可以在事件途中操作事件 (像是對 Observable 做 等行為),轉換成訂閱者有興趣的資料型態。我們也能對透過 RxJava 包裝過的網路請求做相應的處理,例如這次我想處理在 Request 失敗時,讓它再去重試連線,並且每個重試事件的中間需要有一小段 delay 時間。

最簡單的方式就是使用 retry() operator。

以上的 Http Request,會在連線出現問題進入 之前,重新再發射一次 Http Request。如果一直出現錯誤,則總共會發射三次事件,第三次會真正進入

retry() operator 的作用即是會在事件流進入 前重新訂閱原來的 Observable 因而重新再發射出事件。用這個 Http Request 來看,只要錯誤就會重新執行一次 HTTP Request。
一般來說,我們只關注 ,像是 Timeout ⋯等事件才需要重新送 Http Request 。
而且 retry() operator 不能設定 delay 的時間,錯誤發生的當下即馬上送出下一個 Http Request。

順帶一提你可能還會注意到,還有另外一個 operator 叫做 repeat()repeat()retry() 的差別是:retry() 前重新訂閱原 Observable 造成重新發射事件;repeat() 則是在 前重新訂閱原 Observable 因而再重新發射事件。

retry() 實在是過於簡單暴力,我們需要在事件流出現錯誤時判斷是否該繼續重新送出事件,對於錯誤重新發送有更多的控制。我們要改成另外一個 operator 叫


使用 App Bundle 前的必要設定

Image for post
Image for post
WATCH THIS!!

2017 年 Google 推出了 Google Play 應用程式簽署,讓開發者可以將自己的 key 上傳至 Google Play Console,交由 Google 保管。另外還能產生一組專門用來上傳新的 APK/App Bundle 的 upload key,如果不小心把這組 upload key 弄丟,還能透過 Google Play Console 更換一組新的。
Google Play 應用簽署其中一個好處是 Google Play 會幫忙處理 Multiple APK 的簽名,如果專案需要輸出 Multiple APK 不再需要自己處理各個 APK 的簽名。不過對於大部分的開發者來說,遷移至 Google Play 應用程式簽署的好處,是可以使用 App Bundle

如果你目前建立的是全新專案,Google Play Console 會在建立新專案時提供 Google Play 應用程式簽署的相關教學,基本上透過教學引導即能快速設定好。
通常既有專案中,我們早已使用某一個 keystore 行之有年。而這篇文章著重於如何由現有專案的 key 遷移至 Google Play 應用程式簽署,並且會補上 upload key 設定的步驟,設定一次完整的搬遷步驟。

首先開啟 Google Play Console 頁面,找到左側側邊欄的「版本管理」選項,點擊「應用程式簽署」。

Image for post
Image for post

如果你是第一次進到這個頁面,應該會跳出教學頁面。跳選進入內頁,這邊想將目前現有的 key 轉換成使用 Google Play 應用程式簽署,故選擇第二個選項「從 Java 金鑰庫匯出並上傳金鑰」。

Image for post
Image for post

先確認自己電腦中是否有安裝 Java 8 或以上的版本,可以透過終端機,並輸入:

$ java -version

來確定電腦中安裝的 Java 版本。確認後,下載 Google Play Console 提供的 PEPK 工具。你可以將終端機的目錄切換至 PEPK 工具與 keystore 檔案所在的資料夾,並鍵入以下指令來建立應用程式簽署金鑰檔案 (副檔名為 pem 的檔案):

$ java -jar pepk.jar --keystore=<your_keystore_file_name>.jks --alias=<your_key_alias> --output=<file_name>.pem…

About

Ray Yuan Liou

A Mobile App and Game Developer.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store