Android14原生PackageInstaller安裝某些apk報(bào)錯(cuò)問題
最近遇到Android14安裝客戶一個(gè)大型app的時(shí)候,執(zhí)行到開始安裝的時(shí)候就直接閃退了,查看log發(fā)現(xiàn)下面報(bào)錯(cuò):
03-25 18:01:29.531 3085 3085 E AndroidRuntime: java.lang.RuntimeException: Could not copy bitmap to parcel blob. 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.graphics.Bitmap.nativeWriteToParcel(Native Method) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.graphics.Bitmap.writeToParcel(Bitmap.java:2271) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeParcelable(Parcel.java:2606) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageUtil$AppSnippet.writeToParcel(PackageUtil.java:151) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeParcelable(Parcel.java:2606) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeValue(Parcel.java:2507) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeValue(Parcel.java:2384) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeArrayMapInternal(Parcel.java:1320) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1843) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Bundle.writeToParcel(Bundle.java:1389) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeBundle(Parcel.java:1389) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.content.Intent.writeToParcel(Intent.java:11826) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Parcel.writeTypedObject(Parcel.java:2225) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:2077) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Instrumentation.execStartActivity(Instrumentation.java:1873) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Activity.startActivityForResult(Activity.java:5634) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Activity.startActivityForResult(Activity.java:5592) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Activity.startActivity(Activity.java:6090) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.Activity.startActivity(Activity.java:6057) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageInstallerActivity.startInstall(PackageInstallerActivity.java:70 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageInstallerActivity.lambda$bindUi$0(PackageInstallerActivity.java 79) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageInstallerActivity.$r8$lambda$RCIm8wl1VPqdfQgkgmrBIDbuvOQ(Packag nstallerActivity.java:0) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.PackageInstallerActivity$$ExternalSyntheticLambda0.onClick(R8$$Synthet Class:0) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.packageinstaller.AlertController$ButtonHandler.handleMessage(AlertController.java:144) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:205) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.os.Looper.loop(Looper.java:294) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8248) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) 03-25 18:01:29.531 3085 3085 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) 需要如何修改函數(shù)避免錯(cuò)誤。
根據(jù)上面報(bào)錯(cuò)定位到frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\PackageUtil.java 中的writeToParcel函數(shù)。
public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(label.toString()); Bitmap bmp = getBitmapFromDrawable(icon); dest.writeParcelable(bmp, 0); }
這個(gè)函數(shù)是將bmp文件轉(zhuǎn)為parcel blob報(bào)錯(cuò)??赡茉蚴荁itmap 過大。解決辦法如下:
解決方案:
方案 1:壓縮 Bitmap 再傳遞
由于 writeParcelable
可能不適用于大 Bitmap
,可以用 ByteArrayOutputStream
壓縮 Bitmap
成 byte[]
,然后傳輸:
public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(label.toString()); Bitmap bmp = getBitmapFromDrawable(icon); if (bmp != null) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] byteArray = stream.toByteArray(); dest.writeByteArray(byteArray); System.out.println("Compressed Bitmap size: " + byteArray.length + " bytes"); } else { dest.writeByteArray(null); } }
在 readFromParcel
時(shí),需要用 BitmapFactory.decodeByteArray()
還原 Bitmap
:
byte[] byteArray = source.readByteArray(); Bitmap bmp = (byteArray != null) ? BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length) : null;
方案 2:限制 Bitmap 大小
如果你仍然要用 writeParcelable
傳輸 Bitmap
,可以先縮小 Bitmap
,比如:
public Bitmap getResizedBitmap(Bitmap bmp, int maxSize) { int width = bmp.getWidth(); int height = bmp.getHeight(); float scale = Math.min((float) maxSize / width, (float) maxSize / height); int newWidth = Math.round(scale * width); int newHeight = Math.round(scale * height); return Bitmap.createScaledBitmap(bmp, newWidth, newHeight, true); }
然后在 writeToParcel
里:
Bitmap bmp = getBitmapFromDrawable(icon); if (bmp != null) { Bitmap resizedBmp = getResizedBitmap(bmp, 200); // 200px 限制大小 dest.writeParcelable(resizedBmp, flags); }
方案 3:避免 Bitmap 傳輸,使用資源 ID
如果 Bitmap
是來自 Drawable
或 資源文件
,最好傳遞資源 ID,而不是 Bitmap
本身:
dest.writeInt(iconResId);
然后在 readFromParcel
里:
int iconResId = source.readInt(); Drawable icon = context.getResources().getDrawable(iconResId, null);
總結(jié):
- 推薦方案 1:壓縮
Bitmap
并使用writeByteArray()
傳輸。 - 如果必須用
writeParcelable
:限制Bitmap
大?。ǚ桨?2)。 - 如果
Bitmap
來源于資源:傳遞資源 ID 而不是Bitmap
(方案 3)。
到此這篇關(guān)于Android14原生PackageInstaller安裝某些apk報(bào)錯(cuò)問題的文章就介紹到這了,更多相關(guān)Android14原生PackageInstaller安裝apk報(bào)錯(cuò)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android開機(jī)自啟動(dòng)服務(wù)的實(shí)現(xiàn)方法
Android開機(jī)自啟動(dòng)服務(wù)的實(shí)現(xiàn)方法,需要的朋友可以參考一下2013-05-05Android屏幕手勢(shì)檢測(cè)的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android屏幕手勢(shì)檢測(cè)的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-11-11Android編程實(shí)現(xiàn)全局獲取Context及使用Intent傳遞對(duì)象的方法詳解
這篇文章主要介紹了Android編程實(shí)現(xiàn)全局獲取Context及使用Intent傳遞對(duì)象的方法,結(jié)合實(shí)例形式分析了Android全局Context的獲取及Intent傳遞對(duì)象的具體操作方法,需要的朋友可以參考下2017-08-08Android入門之讀寫本地文件的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Android如何實(shí)現(xiàn)讀寫本地文件的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Android有一定的幫助,需要的可以參考一下2022-12-12Android實(shí)現(xiàn)擴(kuò)展Menu的方法
這篇文章主要介紹了Android實(shí)現(xiàn)擴(kuò)展Menu的方法,涉及Android操作menu菜單的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10Android添加指紋解鎖功能的實(shí)現(xiàn)代碼
當(dāng)開發(fā)的APP需要加密驗(yàn)證時(shí)可以考慮添加系統(tǒng)指紋解鎖功能。這篇文章主要介紹了Android添加指紋解鎖功能的實(shí)現(xiàn)代碼,需要的朋友可以參考下2018-07-07ubuntu 12.10 上 android 編譯環(huán)境搭建的深入解析
本篇文章是對(duì)ubuntu 12.10上android 編譯環(huán)境的搭建進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Android 軟鍵盤狀態(tài)并隱藏輸入法的實(shí)例
這篇文章主要介紹了Android 軟鍵盤狀態(tài)并隱藏輸入法的實(shí)例的相關(guān)資料,這里提供實(shí)例實(shí)現(xiàn)軟鍵盤切換并隱藏輸入法的鍵盤,需要的朋友可以參考下2017-09-09