Wednesday, August 16, 2017

2017 又再 Android

好日唔寫下 android app, 每次開番個 android studio 都有好多新野.
以下係一邊開一邊記低既, 可能有D野白痴左, 希望唔會衰太多.  唔理咁多, 行到先再諗.

第一件事, 一開就話由 2.2.2 升上 2.3.2, 無問題, go ahead 升左先.
呢樣唔需要理掛, 反正無選擇, 直升就係.

今次主要目的, 係睇下點解家陣 IAmHere  回傳既地址, 好多時會出左空白.
想睇下有無可能記低每日回傳既資料, 有時間夜晚再研究.

升級完 2.3.2 之後, 又會問 Gradle Plugin 既升級, 去吧.  唔知今次會唔會又有新問題.

按左 [Updaate], 就慢慢等佢 refresh 左個 "IAmHere" Gradle project.
唔知係咪公司機慢, 又要經 proxy 上網, 真係等左好耐, 但下面既 status 不斷變緊, 唔係 hang 機.
大約 5 分鐘後, 就用得喇......成喇, 成半年無掂過, 真係有D唔識用了.

有理無理, 按個 play 睇下先, 都唔記得點起個 VM 出黎, 唔知有無剷其他野果陣剷左.
好在, 仲有一個 Virtual Device,  雖然 Nexus 5 舊左D. 唔理咁多, 試住先.  [OK] 行到再改.

頂...又 out-of-date, 照 [OK]

Default 2GB 玩住先.

又係等佢裝, 慢慢等, 唔好心急, 比D耐性, 好快就裝完.


之後起左個 VM 出黎,

再等佢 build 一輪, 終於見到了.


用 VM 唔係好記得可以點試, 因為個 app 要收 SMS 再回傳.  都係要用番真機至試得.
手頭得一部手機, 試條鐵咩.....原來, 真係有條鐵比我試.

唔知係咪新加既, 定係我一直無留意, 佢個 VM 右邊有條 menu bar.

按落去最底既 "...", 可以 set location,

仲可以試電話收 sms

收到又認到, 就係唔識出地址....呢個就係我最近成日見既問題, 有回傳, 無地址.

未知係 emulator 既問題, 定真係 hit 到我想 trace 既 bug.
但可以出現到, 都係一個希望, 準備 debug 去.

嘗試行 google map 睇下有無地圖, 佢話我無 network 添.

再上網搵下, 佢話有得設定 network 既:  Set Up Android Emulator Networking

不過, 佢既  Extended controls 係咁 (iOS 有少少唔同樣, 重點係內容):


但係我果個係咁, 無呢個 proxy setting 既?

唔通因為我個 VM 太舊?  試下起個新既再來.

起左個新既, 跟番我D機用 android 6.0 都係唔得.  唔通真係只有 iOS 既 android studio 至得.
無得設定 proxy 就上唔到網, 唔比我睇 google map 添.
唯有番去唔經 proxy 再試.

每 次 close 再開, 都仲係有好多野要 update, Android D 野轉得快, 我幾乎一年至玩一陣, 次次都好多升級.  有排至升齊.

或者升哂再試下.


Tuesday, January 3, 2017

.gitignore

Android project 用 git 既話, 入面個 .gitignore 我仲執緊.
收得太緊, 可能會漏蕉.  放得太鬆, 可能會好煩.

家陣不斷左抄右抄, 希望唔會太鬆, 又唔會太緊喇.....
有 D 可能九唔搭八, 因為來自不同 project type (連 Visual Studio 都有).


#gradle properties (may contain passwords)
gradle.properties

# idea (copied from .gitignore generated by Android Studio)
/.idea/workspace.xml
/.idea/libraries

# Built application files
*.apk
*.ap_

# Files for the Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/

# Gradle files
.gradle/
build/
*/build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# =========================
# Operating System Files
# =========================

# OSX
# =========================

.DS_Store
.AppleDouble
.LSOverride

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

# Windows
# =========================

# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msm
*.msp

# Windows shortcuts
*.lnk

# Intellij project files
*.iml
*.ipr
*.iws
.idea/

出事篇: targetSdkVersion - 23 or above

之前手痕, 見定陣兩部電話, 一部 Android 6.0 另一部 Android 7.1, 心諗主力用既機都升左上 6.0 以上, 只係得番 D tablet 同阿仔部松用舊版, 就將 Sdk version 提升一下.

minSdkVersion: 19

呢個 minSdkVersion 因為 createFromPdu 既緣故已經升左上 19 (詳情可以睇番 Deprecated methods).

既然個名叫 min...就更係有細得細, 而最少要 19, 咪 keep 住 19 先.


targetSdkVersion: 22

呢個其實我都唔係太明白, 基本上講明 minSdkVersion 係 19, 即係 19 或以上都要 work, 咁仲加個 target 有乜用?  睇番網上講, target 最好 set 到你認為行到個 app 最大既 version, 等佢可以同你 check 下有無新野係唔夾既.  聽落幾理想, 我個人保守少少, 就試改成 23 (跟我手上部電話先).

改完用番部 tablet 試, 因為佢係最低版本 (仲係 食緊 KitKat), 諗住佢得就實得.
試好哂, 諗住掂了.

點知幾日後, 幫人裝 app, 發覺出事, 唔識攞 permission.  初時都唔知乜事, 不斷 fallback, 發覺係轉 SdkVersion 呢下出事.
好在, 呢個改動既同時, 無改 program, 咁好明顯就係呢度問題.  如果唔係, 真係有排 debug.

又再上網搵下, 原來 Android 自 API Level 23 開始, 改左 permission 既做法.
以前一裝 app, 你就要同佢講, 接唔接受個 app 要既 permission, 一係就比哂, 一係就唔裝.
自 API Level 23 (Android 6.0) 開始, 用家既自由度大左 (不過又煩左), 裝 app 唔問, 開 app 都唔問 (其實睇 programmer 點寫), 盡量做到有需要至問.

咁就出事喇, 我本身無加入中途問人攞 permission 既 code (鬼咩, 之前都無呢樣野), 而佢又改左裝 app 果下唔問, 結果就完全唔問, 即係無 permission 了.  點解之前又試唔出?  皆因自己用左部 Android 4.4 既機試, 而 Android 4.4 既機係裝果下就要攞 permission, 所以一開始就有哂了.

本來加番 require permission 既 code 就得, 但有時真係唔 sure 邊度有漏 (analyser 可以同你 check), 安全起見, 改番 裝果下問左先, 反正自己既 app,  自己點會唔信喎.

結果, targetSdkVersion 就變番去 22 了.

Wednesday, December 28, 2016

Deprecated methods

每次 android API 升級, 除左加入新野之後, 都會有 D 舊野會被清理.
萬一你用左 D 會被清走既舊野, 就要準備改 code 了.

Google 既做法, 係會先提醒你某 D 野就快死我, 今次比你過, 下次就唔包了.
如果唔想出事至急急腳搵解藥, 可以叫佢每次都 check 埋有邊 D 野就快死.

好簡單, 只要在 build.gradle 加入下面幾行就得了.
為左唔想影響咁大, 改 Module:app 自己既 build.gradle 好了, 將呢幾句加落最尾就得,

tasks.withType(JavaCompile) {
    options.compilerArgs << "-Xlint:deprecation"}

之後再  build APK, 就會出唔到了, 講埋邊度唔得, 原來係 SmsMessage.createFromPdu 出事:
E:\SourceTree\WhereAreYou\app\src\main\java\org\super169\findlocation\FindLocationActivity.java:189: warning: [deprecation] createFromPdu(byte[]) in SmsMessage has been deprecated                    SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[i]);
又要上網搵笨法解決了. (1) 最簡單既方法, 咪跟佢既 syntax 比埋個  format 佢就得  (API Level 23) String format = extras.getString("format"); SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[i], format);
世事總係無咁好既, 呢個 syntax 係 API Level 23 開始至用得, 即係要改  minSdkVersion 去到 23 或以上, 即係 Android 6.0 Marshmallow 之後既機至用到, 太過份了. 




(2) 用  Telephony 先攞哂 d msg 再慢慢睇  (API Level 19)



SmsMessage[] msgs = msgs = android.provider.Telephony.Sms.Intents.getMessagesFromIntent(intent);
for (int i = 0; i < pdus.length; i++) {
    SmsMessage message = msgs[i];
今次好 D, API Level 19 就有了 (即係 Android 4.4 KitKat 開始).  所以, 針對 SmsMessage.createFromPdu 可以有以下幾個方案:
  1. 唔鬼理佢, 反正家陣仲用得, 可以 keep 住 midSdkVersion 18
  2. 轉用 Telephony 去讀 message, 而 midSdkVersion 只係升上 19, 影響唔算大
  3. 用 SmsMessage.createFromPdu 既新 Syntax, 但 midSdkVersion 就要上 23 至得

Google Play Services

最後一項, 就係升級 Google Play Services.
本來以為只係改番個 version, 由 8.4.0 改成 10.0.1 就得, 點知出左 error.

(1) IAmHere

先由簡單既做起, IAmHere 無咁多野, 只係讀 location, 點解會出事?
如果直接改成 10.0.1, build 無問題, 出 APK 就會咁:

Error:Execution failed for task ':app:transformClassesWithDexForDebug'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536
網上搵下, 大致係因為係 DexIndex 上限係預設左 65535, 當你個 program 大多野加入去, 就會爆.
之前懶慣左, 成套 Google Play Services 加哂入去, 而 Google 又越加越多功能, 咪爆左囉.
解決方法, 一係加大佢, 一係就用少 D.

其實, Google play service 可以拆開黎加, 佢既 Setup Guide 有資料講有幾多舊既.
唔好咁懶了, 用左邊個咪加邊個囉.
就以 IAmHere 為例, 用得幾多 service?  咪就係一個 location service  咁大把, 唔駛成套加哂.
所以, 只要改成咁就得了:


  • compile 'com.google.android.gms:play-services-location:10.0.1'


(2) WhereAreYou

同樣, WhereAreYou 都係用左 location service 咁大把, 當然又係改番指定 location 就夠.
不過, 世事就係無咁完美既, 轉成 com.google.android.gms:play-services-location:8.4.0 無問題,
但一改成 10.0.1 就出錯了.
注意, Build Project 係無 error 既, 但係出 APK 就死得.

首先, 係會無哂 maps 既 service.  呢樣少事, google 將 maps 由 location 入面分左出黎, 加番呢句就得:
  • compile 'com.google.android.gms:play-services-maps:10.0.1'

不過, 之後就真係唔得了, 在 FindLocationActivity.jav 入面用到既 getMap() 既 method 無左了.
網上睇家陣要改用 getMapAsync(), 但 async mode 既做法又唔同了.

首先, getMapAsync 係 Async call, 咁本來放佢後面既 code, 就要拆出黎, 放去一個 callback method 度.
而 getMapAsync 需要一個 implement 左 OnMapReadyCallback 既 class, 咁最簡單就係將原本個 activity class (即係 FindLocationActivity) 再 implement 埋佢.

public class FindLocationActivity extends FragmentActivity
implements ConnectionCallbacks,
OnConnectionFailedListener,
LocationListener,
OnMyLocationButtonClickListener,
OnMapReadyCallback { .....
之後, 當然係加番有關既 method 喇, 而 OnMapReadyCallback 只係需要一個 OnMapReady 既 method, 而佢就會收到一個 GoogleMap 既 parameter, 順理成章, 就係將原本做完 getMap() 既 code, 放入去 呢個 method 就得了.

@Override
public void onMapReady(GoogleMap map) {
    mMap = map;
    if (mMap != null) {
        mMap.setMyLocationEnabled(true);
        mMap.setOnMyLocationButtonClickListener(this);
        mMap.getUiSettings().setZoomControlsEnabled(false);
    }
}

改完呢度, 基本上可以行得了.


一點手尾.....

不過, 其實 Build APK 果陣, 出左句野:
Note: E:\SourceTree\WhereAreYou\app\src\main\java\org\super169\findlocation\FindLocationActivity.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
呢個就同 getMap 一樣, 今次仲可以用, 遲下就會無.
之後會拆解埋佢, 咁就可以玩得耐 D.



又有野就黎唔用得, 同 getMap 之前一樣, 今次仲可以用, 遲下就會無.
懶既可以唔理佢, 反正今水仲用得, 有時間就睇下發生乜事.

由於 default 係比你過既, 所以唔知邊度死, 跟佢講 Recompile with -Xlint:deprecation for details.
打開 build.gradle, 加呢段野落最尾就得:

tasks.withType(JavaCompile) {
    options.compilerArgs << "-Xlint:deprecation"}

之後再  build APK, 就會出唔到了, 講埋邊度唔得, 原來係 SmsMessage.createFromPdu 出事:

E:\SourceTree\WhereAreYou\app\src\main\java\org\super169\findlocation\FindLocationActivity.java:189: warning: [deprecation] createFromPdu(byte[]) in SmsMessage has been deprecated
                    SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[i]);
又要上網搵笨法解決了.

本來, 最簡單既方法, 咪跟佢既 syntax 比埋個  format 佢就得:
String format = extras.getString("format");
SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[i], format);
世事總係無咁好既, 呢個 syntax 係 API Level 23 開始至用得, 即係要改  minSdkVersion 去到 23 或以上, 即係 Android 6.0 Marshmallow 之後既機至用到, 太過份了.

另一個方法, 就係用  Telephony, 先攞哂 d msg 再慢慢睇.

SmsMessage[] msgs = msgs = android.provider.Telephony.Sms.Intents.getMessagesFromIntent(intent);
for (int i = 0; i < msgs.length; i++) {
    SmsMessage message = msgs[i];


今次好 D, API Level 19 就有了 (即係 4.4 KitKat 開始).

所以, 針對 SmsMessage.createFromPdu 可以有以下幾個方案:


  1. 唔鬼理佢, 反正家陣仲用得, 可以 keep 住 midSdkVersion 18
  2. 轉用 Telephony 去讀 message, 而 midSdkVersion 只係升上 19, 影響唔算大
  3. 用 SmsMessage.createFromPdu 既新 Syntax, 但 midSdkVersion 就要上 23 至得
最後, 我暫時用第 2 個方案, 費事下次就要改.  



啟用 Google Maps API

如果只係 upgrade Android Studio, 以下既野唔需要做, 因為應該已經做左.

不過, 如果裝左部新機, 又或開左個新 project  想用 Google API 就要了.


(1) 要搵出自己部機既 SHA1 key (唔係跟機的, 重裝 Android studio 都會變既)

"C:\Program Files\Java\jre1.8.0_111\bin\keytool.exe" -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android


記住 將上面  SHA1 果串野, 備用

(2) 打開 Google APIs Manager , 睇 D API Projects



(3) 去 Credentials 果頁, 搵番 FindLocation



(4) 條 key 應該已經加左入 AndroidManifest.xml 入面, 唔放心可以 check 下先.


(5) 如果想當新  project, 可以 create 條新 key 比佢, 不過今次唔需要.

(6) 如果係新機, 就要加番部機入去.  安全點, 就算 upgrade 完都  check check.
     Click 落 FindLocation 果度, 可以入去睇下有乜野機加左.
     對番上面 (1) 既 SHA1, 如果本身有就唔駛做野, 無就加番落去.


   
       


dependencies version

Android project 既 dependencies 既 version, 又係有點煩既野.
當然, 如果你唔升級, 其實一般唔改都無問題.
不過, 一如以往, 有新就玩新, 我都係貪新既人, 每次都會嘗試升級.

在 IAmHere 同 WhereAreU 入面, 基本上只有兩個 dependencies


  • compile 'com.android.support:appcompat-v7:25.1.0'
  • compile 'com.google.android.gms:play-services:10.0.1'


呢兩件野, 其實我都唔記得邊度用左, 而且, 最煩係唔多識 check 個 version 要點填.
之前好鐘意用 + 結尾, 即係大過呢個就得.
不過,  佢會話咁樣唔係咁好, 叫你最好指定一個.


咁點樣搵家陣最新邊個呢, 我都係網上睇, 估估下.


Support Library
  • compile 'com.android.support:appcompat-v7:<version>'
可以去呢度睇最新既 version: Recent Support Library Revisions


Google API Service:
  • compile 'com.google.android.gms:play-services:<version>'
可以去呢度睇最新既 version:  Google APIs for Android - Release Notes



世事往往無咁順利既, 當改完個 Google API Service 既 version, 再 compile 出 APK, 就會出事.

在 WhereAreU 中, Clean Project 都 build 到, 但係 Build APK 就會出 Error:

  • Error:(233, 21) error: cannot find symbol method getMap()
getMap 既 method, 已經 out 左, 網上教要改用 getMapAsyc(), 但係 getMapAsync 要比 OnMapReadyCallback.  我之前係用 sync mode 去寫既, 要睇下可唔可以直接將後尾既野放入 callback 以 async  mode 去做.  暫時都係唔改住.

其實, 除左 getMap() 之外, 仲有少系問題既, 安全起見, 都係攪到舊野 compile 到先.
暫時唔升級 Google API Service, 之後會嘗試改番既.
之前係用 8.4.0 既, 所以改番轉頭就算, 過左海就神仙.

  • compile 'com.google.android.gms:play-services:8.4.0'
記住, 每次改完 build.gradle, 都要按下右上既 "Sync Now" 等佢 sync 一野.

改完再 Clean Project, 會見到佢提你 getMap() 已經 out 左, 不過 8.4.0 仲比你用到, 頂住先.