發表文章

目前顯示的是有「Android」標籤的文章

在Ubuntu中建立Android Studio左列圖示

圖片
  Tools > Create Desktop Entry

用pk8和x509.pem產生Android Studio使用的keystore檔

Eclipse與Android Studio用的是keystore檔案,然而AOSP內提供AOSP裡面提供的是pk8和x509.pem檔案,實際上都是一樣的,只是表現格式不同。 AOSP的key一般會在build/target/product/security內,裏面有數個*.pk8和*.x509.pem檔案, 分別對應不同層級的簽章, 有media, shared, platform, test, 以及release release是給OTA包使用,test是ENG工程版使用,platform是系統權限的APP用的, 要用Android.mk幫APP簽系統權限, 要加上 LOCAL_CERTIFICATE := platform 下面這個script是自動,產生mygen.keystore檔案,store密碼是password 要顯示在keystore可使用java內的keytool工具 keytool -list -v -keystore mygen.keystore

解決:安裝測試APP發生INSTALL_FAILED_NO_MATCHING_ABIS的問題

這個INSTALL_FAILED_NO_MATCHING_ABIS問題會發生在安裝APK內有Native Library的APP,例如react-native。關於ABI的說明可參考 官方文件 。

開發Android APP要設定的環境變數及PATH

圖片
這篇彙整一下2021要設定的環境變數,因為開發React-Native, Flutter等都會使用到command line tool,然後因為近期Google有釋出新的command line tool,所以我也重新調整了一下環境變數

使用put/get取得或設定Android Settings.Global數值

若有需要讀寫Android系統內Java所儲存的global數值,以下以display_outputmode_auto作為範例 取得 settings get global display_outputmode_auto 設置 settings put global display_outputmode_auto 1 settings put global display_outputmode_auto 0 問題 如果出現下面錯誤表示需要高於system的權限 settings put global display_outputmode_auto 1 Error while accessing settings provider java.lang.SecurityException: null from uid 1000 not allowed to perform WRITE_SETTINGS     at android.os.Parcel.readException(Parcel.java:1465)     at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:185)     at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137)     at android.content.ContentProviderProxy.call(ContentProviderNative.java:636)     at com.android.commands.settings.SettingsCmd.putForUser(SettingsCmd.java:208)     at com.android.commands.settings.SettingsCmd.run(SettingsCmd.java:137)     at com.android.commands.settings.Setti...

Android模擬器上跑只有arm library的App方法

  感謝Google和Arm的努力,我們現在要在Android模擬器上跑只有arm library的App,只需要 選擇A ndroid 11 (API 30)俱備Google Play的x86映像檔 就可以了 來源:  https://android-developers.googleblog.com/2020/03/run-arm-apps-on-android-emulator.html 因為映像檔裡包含了轉譯層library $ getprop | grep native [ro.dalvik.vm.native.bridge]: [libndk_translation.so] [ro.enable.native.bridge.exec]: [1] 搜尋以前的文章,要用x86跑arm以前只能用 Nexus Player包含的libhoudini重新打包boot和ramdisk,步驟煩瑣,現在都簡化啦!

解決monkeyrunner無法在Windows中執行

以下彙整解決monkeyrunner無法在Windows中執行的方法

Android App跳出Alert對話框

Android App跳出Alert對話框範例Code如下:  設定中間的按鈕 setNeutralButton 設定左邊的按鈕 setPositiveButton 設定右邊的按鈕 setNegativeButton 實際上positive是用以表示"同意", negative是用以表示"反對"或"取消", 跟左右邊沒有直接關係, 所以在有些裝置的主題上, 這個按鈕的左右邊位置會是反的,  不用覺得太驚訝。 參考:  http://toimy.blogspot.tw/2010/08/android-alertdialog.html 2020-11-02補充: 如果你遭遇以下錯誤可以把AlertDialog.Builder的建構子參數,從getContext()改成this即可 java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity. AlertDialog alertDialog = new AlertDialog.Builder( this ).create(); 或是如果你要顯示的Activity是MainActivity的話 AlertDialog alertDialog = new AlertDialog.Builder( MainActivity.this ).create(); 這裡的問題是因為 Android內建的android.app.AlertDialog.Builder跟android.support.v7.app.AlertDialog的AlertDialog.Builder不太一樣所致 https://developer.android.com/reference/android/app/AlertDialog.Builder 另外,還有套用theme的寫法 new AlertDialog.Builder(MainActivity.this, R.style.Theme_AppCompat_Light_Dialog_Alert) 參考: https://givemepass.blogspot.com/2015...

用blueStack,夜神模擬器開發app

圖片
模擬器adb連線 不用設定甚麼, 用 adb連線 夜神模擬器 adb connect 127.0.0.1:62001 用adb連線 BlueStacks 需先從設定開啟adb功能(如圖) adb connect 127.0.0.1:5555

RN:Android裝置透過wifi/ethernet連線開發APP

RN官網上有寫到透過usb線開發,是使用adb reverse來完成的。但是透過wifi/ethernet連線的開發方式我是有看沒有懂,所以這裡簡短紀錄一下確認過的做法。 透過wifi/ethernet連線開發APP 首先當然,你要知道android裝置要可以透過wifi/ethernet連線功能;如無法確定,一般都是用usb,如果你的裝置只能usb就請參考官網的解說就好。 0. 將android裝置連線到同一個wifi/ethernet 因為要透過wifi/ethernet,所以要把開發電腦跟android裝置連線到同一個wifi/ethernet,然後到android的wifi網路設定點詳細看一下IP位址。 1. 連線到該裝置 我的目標裝置IP是192.168.1.101,adb的埠號5555。 adb connect 192.168.1.101:5555 2. 確認可進入該裝置 adb shell 若你的電腦有多個adb device,要改用 adb -s 192.168.1.101:5555 shell 若成功後請輸入exit離開該裝置 如果顯示的是無法連到斷線的裝置,表示你的電腦或網路有阻擋連線,請確認已經把adb加入到防火牆白名單 2.1 開啟Win10預設Defender防火嗆 若你的電腦使用Window10預設的Defender,請前往設定>搜尋框輸入"防火牆">選取"允許應用程式透過Windows Defender防火牆通訊">點擊變更設定 找到adb.exe執行檔加入白名單 3. 啟動你的RN應用程式 npm run android 這時你的APP應該會被RN工具裝到你的Android裝置上,並被叫起。不過這時候畫面應該是顯示無法載入bundle。 4. 啟動RN的開發選項並輸入電腦IP及埠號 adb shell input keyevent 82 接著點選進入Dev Settings,點選Debug server host for device。 上面輸入的82其實就是KEYCODE_MENU,可以叫起RN開發選項。 接著在android裝置上輸入你電腦IP和埠號(以我電腦為例是192.168.1.115:8081)。如果你的android裝置不好輸入文字,可以用adb shell in...

設定networkSecurityConfig讓APP可用http存取特定domain

  在用APP測試iot大平台時,有部份api是以http來存取的, android現在版本有限制http的連線, 所以需要加domain才能存取,可參考 官方說明 我這裡用的network_security_config.xml如下 <? xml version ="1.0" encoding ="utf-8" ?> <network-security-config> <base-config> <trust-anchors> <certificates src ="system" /> </trust-anchors> </base-config> <domain-config cleartextTrafficPermitted ="true" > <domain includeSubdomains ="true" > iot.cht.com.tw </domain> </domain-config> </network-security-config> 並在AndroidManifest.xml中的application tag的屬性中加入 android :networkSecurityConfig ="@xml/network_security_config"

AOSP差分OTA中加入前後版MD5和版本號紀錄

--- build/tools/releasetools/ota_from_target_files +++ build/tools/releasetools/ota_from_target_files @@ -642,6 +642,15 @@ def LoadSystemFiles(z):        out[fn] = common.File(fn, data)    return out +def GetMD5(path): +    tp_file = open(path,"r") +    if tp_file == False: +        print("WARNING: cannot generate MD5".path) +        return "NONE" +    re_value = hashlib.md5(tp_file.read()).hexdigest() +    tp_file.close() +    del tp_file +    return re_value  def GetBuildProp(prop, info_dict):    """Return the fingerprint of the build of a given target-files info_dict.""" @@ -665,6 +674,12 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):                                           OPTIONS.source_inf...

設定TextView當加入文字後會自動捲到最底(Auto-scrolling TextView)

這裡展示的是在android的基本範例碼中加入可以自動捲到最底的TextView, 網路有許多解答關於auto-scrolling的作法,但是總是有缺點,例如透過修改Movement方法來完成,但是對於TextView下方還有其他元件的Layout,總是無法自動捲動顯示最後幾排文字。 在ConstraintLayout中,我們透過設置高度為0dp,讓ConstraintLayout能夠正確將TextView的當前的高度資訊反映在getHeight()函數。隨後再為TextView加入TextChangedListener讓,讓新的文字被append到TextView時,設定gravity的方法,讓TextView會自動捲到最底的文字位置。 若您還希望可以用滑鼠/觸控方式移動到上下部分,只要再加入下面這行即可 txtMsgView.setMovementMethod(new ScrollingMovementMethod());

解決Android Studio編譯錯誤:Error: Invoke-customs are only supported starting with Android O (--min-api 26)

Error: Invoke-customs are only supported starting with Android O (--min-api 26) build.gradle文件中android下增加: compileOptions {     sourceCompatibility JavaVersion.VERSION_1_8     targetCompatibility JavaVersion.VERSION_1_8 } https://blog.csdn.net/yinxing2008/article/details/83619313

設定ImageView圖片的幾種方式

直接設定Resource ID imageView.setImageResource(R.drawable.your_image); Uri直接設定 import android.net.Uri; Uri uri = 圖片/文件選取器取的Uri imageView.setImageURI(uri); 從Uri開啟檔案再設定 import android.net.Uri; import android.graphics.BitmapFactory; try {     InputStream inputStream = getContentResolver().openInputStream(uri);     imageView.setImageBitmap(BitmapFactory.decodeStream(inputStream)); } catch (FileNotFoundException fnf) { } uri如果是Content://這種的,基本上都需要取得READ_EXTERNAL_STORAGE權限。 從實際路徑載入檔案 import android.graphics.Bitmap; String path = 看你從哪裡拿來的路徑 Bitmap bmp = BitmapFactory.decodeFile(path); if (bmp != null) {     imageView.setImageBitmap(bmp); } 如果不是APP自己底下的檔案路徑,都需要取得READ_EXTERNAL_STORAGE權限。

長按ImageView開啟選取器取得圖片Uri

加入長按事件     private ImageView imageView; ... onCreate ...         imageView = findViewById(R.id.imageView);         imageView.setOnLongClickListener(new View.OnLongClickListener() {             @Override             public boolean onLongClick(View view) {                 pickFromGallery();                 return true;             }         }); 啟動圖片選取器     /**      * @ref https://androidclarified.com/pick-image-gallery-camera-android/      */     final static int GALLERY_REQUEST_CODE = 0x1000;     private void pickFromGallery() {         Intent intent = new Intent(Intent.ACTION_PICK); // launch gallery app         //Intent intent ...

筆記:分享圖片/文字/HTML到其他App

分享文字/圖片到其他App,例如FB、Line 以前分享文字 以前分享文字,自己寫intent,然後開啟Activity static Intent getSendTextIntent(String text) {     Intent intent = new Intent();     intent.setAction(Intent.ACTION_SEND);     intent.setType("text/plain");     intent.putExtra(Intent.EXTRA_TEXT, text);     return intent; } startActivity(getSendTextIntent("Hello, just do a test!")); 一般還會建議應該再判斷是否可以啟動Activity if (intent.resolveActivity(getPackageManager()) != null) {     startActivity(intent); } 現在分享文字 現在用ShareCompat就好了 import android.support.v4.app. ShareCompat ; 最新的JetPack是引用 import androidx.core.app. ShareCompat ; ShareCompat.IntentBuilder.from( MainActivity .this)         .setType("text/plain")         .setChooserTitle("Share Text")         .setText("Hello, just do a test!")         .startChooser(); 如果要Intent也是可以getIntent...

取得最上層繪製權限

在SDK 23之前,最上層繪製是不需要取得權限的。 在SDK 23之後,最上層繪製需要於啟動系統設定頁處理。 canDrawOverlays用以確認是否可以最上層繪製。 這裡我曾在SONY手機Android 8.0上遇到一個坑。 APP取得權限後馬上使用canDrawOverlays,實際上是已經擁有權限,但是不論如何都無法獲得正確數值,必須關閉APP再重啟才可以確認已擁有權限,這點在網路上也有人分析是系統問題,必須升級系統才會正常。 static public Intent getDrawOverlayPermissionIntent (Context context) { Intent intent = null; if (Build.VERSION. SDK_INT >= 23 ) { intent = new Intent( Settings. ACTION_MANAGE_OVERLAY_PERMISSION , Uri. parse ( "package:" + context.getPackageName())) ; // Workaround: put extras for the key event not handled in Overlay Setting page. intent.putExtra( "extra_prefs_show_button_bar" , true ) ; // show the status bar intent.putExtra( "extra_prefs_show_skip" , false ) ; // skip button is gone intent.putExtra( "extra_prefs_set_next_text" , "" ) ; // next button is gone intent.putExtra( "extra_prefs_set_back_text" , ...

彙整一些取得Android Intent的方便函數

取得Android Home,Launcher2, Launcher3(Androi 7.1/TV), 設定頁, Wifi設定頁 static public Intent getAndroidHomeActivityIntent () { Intent intent = new Intent(Intent. ACTION_MAIN ) ; intent.addCategory(Intent. CATEGORY_HOME ) ; intent.addFlags(Intent. FLAG_ACTIVITY_NEW_TASK ) ; return intent ; } static public Intent getLauncher2ActivityIntent () { Intent intent = new Intent(Intent. ACTION_MAIN ) ; intent.setComponent(ComponentName. unflattenFromString ( "com.android.launcher/com.android.launcher2.Launcher" )) ; intent.addFlags(Intent. FLAG_ACTIVITY_NEW_TASK ) ; return intent ; } static public Intent getLauncher3ActivityIntent () { Intent intent = new Intent(Intent. ACTION_MAIN ) ; intent.setComponent(ComponentName. unflattenFromString ( "com.android.launcher3/com.android.launcher3.Launcher" )) ; intent.addFlags(Intent. FLAG_ACTIVITY_NEW_TASK ) ; return intent ; } static public Intent getSettingActivi...

Android.mk引用aar包

aar是Android Archive檔,在Anroid.mk中使用aar包有三步驟: 1. 先把這些aar模組設定成prebuilt 把aar包下載回來,假設aar包都放在lib目錄內,寫個獨立的Android.mk設為prebuilt include $(CLEAR_VARS) LOCAL_PREBUILT_STATIC_JAVA_LIBARRIES += {aar-package-name-1}:lib/{aar-file-name-1}.aar LOCAL_PREBUILT_STATIC_JAVA_LIBARRIES += {aar-package-name-2}:lib/{aar-file-name-2}.aar ... include $( BUILD_MULTI_PREBUILT ) 2. 表明加入需要使用aar包 LOCAL_STATIC_JAVA_AAR_LIBRARIES += {aar-package-name-1} LOCAL_STATIC_JAVA_AAR_LIBRARIES += {aar-package-name-2} ... 3. 並加入aar的class名稱 編譯程式才會找的到 LOCAL_AAPT_FLAGS += --auto-overlay LOCAL_AAPT_FLAGS += --extra-packages {aar-class-name-1} LOCAL_AAPT_FLAGS += --extra-packages {aar-class-name-2} ...