版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Android開(kāi)發(fā)之做一鍵批量卸載App功能的詳細(xì)講解首先準(zhǔn)備一部已經(jīng)Root的手機(jī),然后打開(kāi)\t"/kf/201807/_blank"Android
Studio,下面我們開(kāi)始快樂(lè)的寫(xiě)代碼吧~首先我們先分析具體的業(yè)務(wù)需求:很簡(jiǎn)單的一個(gè)需求,最主要的功能就是可以卸載App;同時(shí)要求可以批量卸載;既然能夠批量卸載,也就是說(shuō)我們?cè)赨I交互上可以批量選擇;能大量展示待卸載的App。好的我們現(xiàn)在一步一步的來(lái):首先我們先解決最主要的需求,卸載App!有兩種方式可以實(shí)現(xiàn)App卸載:分為靜默方式和非靜默方式。什么是靜默方式?意思就是說(shuō)卸載完全是在\t"/kf/201807/_blank"系統(tǒng)后臺(tái)進(jìn)行的,不需要用戶去點(diǎn)擊確認(rèn)卸載。非靜默方式的意思顯而易見(jiàn),卸載的時(shí)候需要用戶點(diǎn)擊確認(rèn),只有用戶確認(rèn)卸載才會(huì)卸載。我們先說(shuō)非靜默方式卸載:非靜默方式卸載的代碼如下;?123456789publicvoidunstallApp(StringpageName){
IntentuninstallIntent=newIntent();
uninstallIntent.setAction(Intent.ACTION_DELETE);
uninstallIntent.setData(Uri.parse("package:"+pageName));
startActivityForResult(uninstall_intent,1);
}從代碼中我們就可以看出來(lái),這里開(kāi)啟了一個(gè)活動(dòng),也就是所謂的應(yīng)用卸載程序,然后把需要卸載的App包名交給它,它就會(huì)把這個(gè)App給卸載掉。這是正常的App卸載步驟。開(kāi)啟這個(gè)應(yīng)用卸載程序活動(dòng)后,頁(yè)面就會(huì)跳轉(zhuǎn)到卸載頁(yè)面,然后等待用戶點(diǎn)擊確定或者取消,點(diǎn)擊確定就會(huì)執(zhí)行卸載程序,點(diǎn)擊取消就會(huì)回退到原來(lái)的活動(dòng)。在這里我們使用了startActivityForResult()方法來(lái)開(kāi)啟應(yīng)用卸載活動(dòng),目的是為了卸載完成后在回掉函數(shù)里面可以更新原來(lái)的App列表頁(yè)面。非靜默方式代碼非常的簡(jiǎn)單,也非常容易理解,但是這里有個(gè)不足之處,那就是如果我們一次性需要卸載十個(gè)APP應(yīng)用,那么頁(yè)面將會(huì)跳轉(zhuǎn)十次,同時(shí)你也需要點(diǎn)擊十次確定!別忘了我們這里可是要求批量卸載,如果讓用戶去連續(xù)點(diǎn)擊十次確定,這樣會(huì)非常影響用戶體驗(yàn)!所以非靜默方式卸載在這里使用并不是很好,靜默方式是更好的選擇!靜默方式卸載:靜默方式也就是意味著我們需要繞過(guò)安卓的界面,在后臺(tái)執(zhí)行卸載命令,那么怎么做呢?很顯然,當(dāng)然是使用命令了!使用命令的方式我們可以繞過(guò)安卓界面執(zhí)行。這里有兩種卸載App命令:首先是adb命令:adbuninstall<app包名>還有一個(gè)pm命令:pmuninstall<app包名>我們可以看到這兩種命令寫(xiě)法相同,命令的開(kāi)頭不同,那么他們具體的差別在什么地方呢?應(yīng)該用哪一種命令方式?還是兩種命令方式都合適呢?我先不說(shuō)區(qū)別,我們?nèi)?shí)地的測(cè)試一下,首先我們先用adb命令去卸載。代碼如下:?12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152packagecom.example.uninstallapk;
importandroid.util.Log;
importjava.io.DataOutputStream;
/**
*Createdby王將on2018/7/23.
*/
//adb命令翻譯執(zhí)行類publicclassRootCmd{
/***
*@paramcommand
*@return
*/
publicstaticbooleanexusecmd(Stringcommand){
Processprocess=null;
DataOutputStreamos=null;
try{process=Runtime.getRuntime().exec("su");os=newDataOutputStream(process.getOutputStream());os.writeBytes(command+"\n");os.writeBytes("exit\n");os.flush();Log.e("updateFile","======000==writeSuccess======");process.waitFor();
}catch(Exceptione){Log.e("updateFile","======111=writeError======"+e.toString());returnfalse;
}finally{try{
if(os!=null){
os.close();
}
if(process!=null){
process.destroy();
}}catch(Exceptione){
e.printStackTrace();}
}
returntrue;
}
publicstaticvoidunInstallApk(StringpageName){
exusecmd("adbuninstall"+pageName);
}
}主活動(dòng)中我們調(diào)用:?1RootCmd.unInstallApk("com.example.tset");把想要卸載的App包名傳進(jìn)去,運(yùn)行一下,很快你就發(fā)現(xiàn):整個(gè)應(yīng)用崩潰了,出現(xiàn)了ANR問(wèn)題,應(yīng)用無(wú)反應(yīng)。好,我們改為pm命令試一下,結(jié)果發(fā)現(xiàn)成功了!那么現(xiàn)在我們分析一下為什么adb命令會(huì)導(dǎo)致出現(xiàn)ANR問(wèn)題,而pm命令就不會(huì)出現(xiàn)錯(cuò)誤。樂(lè)淘棋牌一個(gè)命令的下達(dá),肯定會(huì)調(diào)用相應(yīng)的方法去處理,只不過(guò)這個(gè)調(diào)用過(guò)程在系統(tǒng)的內(nèi)部,我們外界是看不到的,只能得到命令執(zhí)行的結(jié)果。就好比我們使用命令去卸載App應(yīng)用,同樣也是在內(nèi)部調(diào)用了卸載方法,那么具體這個(gè)方法是什么?在哪里呢?下面我們就去深入的探討一下。Android系統(tǒng)卸載App應(yīng)用都是調(diào)用了一個(gè)類中方法,不管是非靜默模式還是靜默模式,這個(gè)類就是PackageInstaller類。當(dāng)然Android系統(tǒng)安裝App也同樣是調(diào)用的它里面的方法,這個(gè)類功能從它的名字上就可以看出來(lái):打包安裝程序。當(dāng)然這個(gè)類我們?cè)谄匠5拈_(kāi)發(fā)中是用不到的,同樣也是無(wú)法調(diào)用的,這個(gè)類同樣也是一個(gè)底層調(diào)用的類。在這個(gè)類中我們可以找到具體的卸載App方法,讓我們看一下\t"/kf/201807/_blank"源碼:?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172/**
*Uninstallthegivenpackage,removingitcompletelyfromthedevice.This
*methodisonlyavailabletothecurrent"installerofrecord"forthe
*package.
*
*@parampackageNameThepackagetouninstall.
*@paramstatusReceiverWheretodelivertheresult.
*/
publicvoiduninstall(@NonNullStringpackageName,@NonNullIntentSenderstatusReceiver){
uninstall(packageName,0/*flags*/,statusReceiver);
}
/**
*Uninstallthegivenpackage,removingitcompletelyfromthedevice.This
*methodisonlyavailabletothecurrent"installerofrecord"forthe
*package.
*
*@parampackageNameThepackagetouninstall.
*@paramflagsFlagsforuninstall.
*@paramstatusReceiverWheretodelivertheresult.
*
*@hide
*/
publicvoiduninstall(@NonNullStringpackageName,@DeleteFlagsintflags,@NonNullIntentSenderstatusReceiver){
uninstall(newVersionedPackage(packageName,PackageManager.VERSION_CODE_HIGHEST),
flags,statusReceiver);
}
/**
*Uninstallthegivenpackagewithaspecificversioncode,removingit
*completelyfromthedevice.Thismethodisonlyavailabletothecurrent
*"installerofrecord"forthepackage.Iftheversioncodeofthepackage
*doesnotmatchtheonepassedintheversionedpackageargumentthis
*methodisano-op.Use{@linkPackageManager#VERSION_CODE_HIGHEST}to
*uninstallthelatestversionofthepackage.
*
*@paramversionedPackageTheversionedpackagetouninstall.
*@paramstatusReceiverWheretodelivertheresult.
*/
publicvoiduninstall(@NonNullVersionedPackageversionedPackage,@NonNullIntentSenderstatusReceiver){
uninstall(versionedPackage,0/*flags*/,statusReceiver);
}
/**
*Uninstallthegivenpackagewithaspecificversioncode,removingit
*completelyfromthedevice.Thismethodisonlyavailabletothecurrent
*"installerofrecord"forthepackage.Iftheversioncodeofthepackage
*doesnotmatchtheonepassedintheversionedpackageargumentthis
*methodisano-op.Use{@linkPackageManager#VERSION_CODE_HIGHEST}to
*uninstallthelatestversionofthepackage.
*
*@paramversionedPackageTheversionedpackagetouninstall.
*@paramflagsFlagsforuninstall.
*@paramstatusReceiverWheretodelivertheresult.
*
*@hide
*/
@RequiresPermission(anyOf={Manifest.permission.DELETE_PACKAGES,Manifest.permission.REQUEST_DELETE_PACKAGES})
publicvoiduninstall(@NonNullVersionedPackageversionedPackage,@DeleteFlagsintflags,@NonNullIntentSenderstatusReceiver){
Preconditions.checkNotNull(versionedPackage,"versionedPackagecannotbenull");
try{mInstaller.uninstall(versionedPackage,mInstallerPackageName,
flags,statusReceiver,mUserId);
}catch(RemoteExceptione){throwe.rethrowFromSystemServer();
}
}這個(gè)是PackageInstaller類中的四個(gè)uninstall()方法,具體的功能就是卸載App應(yīng)用。當(dāng)然這四個(gè)方法用于卸載不同狀態(tài)的應(yīng)用,具體的使用請(qǐng)看官方給出的描述文檔,這里不再具體的做出分析?,F(xiàn)在我們知道了卸載App調(diào)用的是PackageInstaller類的uninstall()方法,那么這個(gè)和命令的方式有什么關(guān)系呢?我們看一下PackageInstaller類的所處路徑你就明白了,PackageInstaller類的所處路徑為/android/content/pm/PackageInstaller.java,具體在博主這里的完整路徑為:很明顯,在/pm路徑下。pm全稱packagemanager,意思包的管理者,pm命令說(shuō)白了就是包管理命令,進(jìn)一步說(shuō),只有使用pm命令才會(huì)調(diào)用/pm路徑下的底層方法,也就是說(shuō)才會(huì)執(zhí)行包文件的操作。這下你明白為什么使用adb會(huì)導(dǎo)致ANR問(wèn)題了吧,因?yàn)槌绦蛘也坏綀?zhí)行方法?。〖冋嫫迮坪昧?,現(xiàn)在我們解決了最重要的需求,靜默卸載App,那么接下來(lái)的需求就很簡(jiǎn)單實(shí)現(xiàn)了,批量卸載,批量選擇,這里直接使用一個(gè)循環(huán)不停的執(zhí)行卸載命令就好了。按照這個(gè)思路我們開(kāi)始寫(xiě)代碼。首先是界面UI部分:?12345678<!--xmlversion="1.0"encoding="utf-8"--><linearlayoutandroid:layout_height="match_parent"android:layout_width="match_parent"android:orientation="vertical"xmlns:android="/apk/res/android">
<scrollviewandroid:layout_height="1dp"android:layout_weight="10"android:layout_width="match_parent">
<linearlayoutandroid:id="@+id/linear1"android:layout_height="wrap_content"android:layout_width="match_parent"android:orientation="vertical">
</linearlayout>
</scrollview><buttonandroid:id="@+id/start_delete"android:layout_height="1dp"android:layout_weight="1"android:layout_width="match_parent"android:text="一鍵卸載"></button></linearlayout>使用ScrollView嵌套一個(gè)LinearLayout布局來(lái)實(shí)現(xiàn)App列表,其中單個(gè)的App信息使用動(dòng)態(tài)加載的形式添加。下面是一個(gè)App信息子布局:?123456<!--xmlversion="1.0"encoding="utf-8"--><linearlayoutandroid:layout_height="wrap_content"android:layout_width="match_parent"android:orientation="horizontal"xmlns:android="/apk/res/android">
<checkboxandroid:id="@+id/page_id"android:layout_height="wrap_content"android:layout_width="wrap_content">
<textviewandroid:id="@+id/page_name"android:layout_height="wrap_content"android:layout_width="wrap_content"android:text="應(yīng)用包名"android:textcolor="#000000"></textview></checkbox></linearlayout>很簡(jiǎn)單,兩個(gè)控件組成,一個(gè)ChexBox控件提供勾選,一個(gè)TextView用來(lái)展示App的標(biāo)簽。638棋牌接下來(lái)我們就需要寫(xiě)主活動(dòng)中的邏輯性操作了:首先貼上我們的MainActivity代碼:?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121publicclassMainActivityextendsAppCompatActivity{
LinearLayoutlinearLayout;
List<integer>pages=newArrayList<>();
List<view>views=newArrayList<>();
ProgressDialogprogressDialog;
List<packageinfo>packageInfos=newArrayList<>();
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linearLayout=(LinearLayout)findViewById(R.id.linear1);
Buttonbutton=(Button)findViewById(R.id.start_delete);
PackageManagerpackageManager=getPackageManager();
packageInfos=packageManager.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
intid=0;
for(PackageInfopackageInfo:packageInfos){Stringstr=packageInfo.applicationInfo.loadLabel(getPackageManager()).toString();linearLayout.addView(getChoiceView(linearLayout,str,id));id++;
}
button.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){
newDEleteApk().execute();}
});
}
privateViewgetChoiceView(LinearLayoutroot,finalStringpageName,intid){
finalViewview=LayoutInflater.from(this).inflate(R.layout.choice_layout,root,false);
finalCheckBoxcheckBox=(CheckBox)view.findViewById(R.id.page_id);
finalTextViewtextView=(TextView)view.findViewById(R.id.page_name);
view.setTag(id);
checkBox.setTag(view);
checkBox.setOnCheckedChangeListener(newCompoundButton.OnCheckedChangeListener(){@OverridepublicvoidonCheckedChanged(CompoundButtonbuttonView,booleanisChecked){
if(isChecked){
views.add((View)checkBox.getTag());
pages.add((int)view.getTag());
}else{
Viewview1=(View)checkBox.getTag();
views.remove(view1);
pages.remove(getIndexPages((int)view1.getTag()));
}
}
});
textView.setText(pageName);
returnview;
}
publicintgetIndexPages(intid){
intindex=0;
intj=0;
for(inti:pages){if(i==id){
index=j;
break;}j++;
}
returnindex;
}
classDEleteApkextendsAsyncTask{
@Override
protectedvoidonPreExecute(){progressDialog=n
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025版辣椒種植基地農(nóng)業(yè)產(chǎn)業(yè)化合作合同3篇
- 2025廣告制作合同的模板
- 二零二五年度XX工業(yè)園區(qū)污水排放達(dá)標(biāo)處理合同
- 2025版高考政治二輪復(fù)習(xí)專題4中國(guó)特色社會(huì)主義新時(shí)代的經(jīng)濟(jì)建設(shè)3高考典題訓(xùn)練含解析
- 2025版高考數(shù)學(xué)一輪復(fù)習(xí)核心考點(diǎn)精準(zhǔn)研析9.1空間幾何體文含解析北師大版
- 二零二五年度抗滑樁施工環(huán)境保護(hù)與治理合同2篇
- 感恩同行青春揚(yáng)帆新時(shí)代
- 簡(jiǎn)單勞動(dòng)合同電子版范本5篇
- 品牌聯(lián)合推廣廣告投放合同(2篇)
- 二零二五年度建筑工程設(shè)備采購(gòu)合同范本2篇
- 中科院簡(jiǎn)介介紹
- 《小石潭記》教學(xué)實(shí)錄及反思特級(jí)教師-王君
- 【高中語(yǔ)文】《錦瑟》《書(shū)憤》課件+++統(tǒng)編版+高中語(yǔ)文選擇性必修中冊(cè)+
- 醫(yī)療機(jī)構(gòu)(醫(yī)院)停電和突然停電應(yīng)急預(yù)案試題及答案
- 24年海南生物會(huì)考試卷
- 國(guó)家戰(zhàn)略思維課件
- 施工單位自評(píng)報(bào)告
- 招商租金政策方案
- 銀行金庫(kù)集中可行性報(bào)告
- 工程結(jié)算中的風(fēng)險(xiǎn)識(shí)別與防控
- 安全教育培訓(xùn)課件:意識(shí)與態(tài)度
評(píng)論
0/150
提交評(píng)論