Android开发之做一键批量卸载App功能的详细讲解_第1页
Android开发之做一键批量卸载App功能的详细讲解_第2页
Android开发之做一键批量卸载App功能的详细讲解_第3页
Android开发之做一键批量卸载App功能的详细讲解_第4页
Android开发之做一键批量卸载App功能的详细讲解_第5页
已阅读5页,还剩6页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Android开发之做一键批量卸载App功能的详细讲解首先准备一部已经Root的手机,然后打开\t"/kf/201807/_blank"Android

Studio,下面我们开始快乐的写代码吧~首先我们先分析具体的业务需求:很简单的一个需求,最主要的功能就是可以卸载App;同时要求可以批量卸载;既然能够批量卸载,也就是说我们在UI交互上可以批量选择;能大量展示待卸载的App。好的我们现在一步一步的来:首先我们先解决最主要的需求,卸载App!有两种方式可以实现App卸载:分为静默方式和非静默方式。什么是静默方式?意思就是说卸载完全是在\t"/kf/201807/_blank"系统后台进行的,不需要用户去点击确认卸载。非静默方式的意思显而易见,卸载的时候需要用户点击确认,只有用户确认卸载才会卸载。我们先说非静默方式卸载:非静默方式卸载的代码如下;?123456789publicvoidunstallApp(StringpageName){

IntentuninstallIntent=newIntent();

uninstallIntent.setAction(Intent.ACTION_DELETE);

uninstallIntent.setData(Uri.parse("package:"+pageName));

startActivityForResult(uninstall_intent,1);

}从代码中我们就可以看出来,这里开启了一个活动,也就是所谓的应用卸载程序,然后把需要卸载的App包名交给它,它就会把这个App给卸载掉。这是正常的App卸载步骤。开启这个应用卸载程序活动后,页面就会跳转到卸载页面,然后等待用户点击确定或者取消,点击确定就会执行卸载程序,点击取消就会回退到原来的活动。在这里我们使用了startActivityForResult()方法来开启应用卸载活动,目的是为了卸载完成后在回掉函数里面可以更新原来的App列表页面。非静默方式代码非常的简单,也非常容易理解,但是这里有个不足之处,那就是如果我们一次性需要卸载十个APP应用,那么页面将会跳转十次,同时你也需要点击十次确定!别忘了我们这里可是要求批量卸载,如果让用户去连续点击十次确定,这样会非常影响用户体验!所以非静默方式卸载在这里使用并不是很好,静默方式是更好的选择!静默方式卸载:静默方式也就是意味着我们需要绕过安卓的界面,在后台执行卸载命令,那么怎么做呢?很显然,当然是使用命令了!使用命令的方式我们可以绕过安卓界面执行。这里有两种卸载App命令:首先是adb命令:adbuninstall<app包名>还有一个pm命令:pmuninstall<app包名>我们可以看到这两种命令写法相同,命令的开头不同,那么他们具体的差别在什么地方呢?应该用哪一种命令方式?还是两种命令方式都合适呢?我先不说区别,我们去实地的测试一下,首先我们先用adb命令去卸载。代码如下:?12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152packagecom.example.uninstallapk;

importandroid.util.Log;

importjava.io.DataOutputStream;

/**

*Createdby王将on2018/7/23.

*/

//adb命令翻译执行类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);

}

}主活动中我们调用:?1RootCmd.unInstallApk("com.example.tset");把想要卸载的App包名传进去,运行一下,很快你就发现:整个应用崩溃了,出现了ANR问题,应用无反应。好,我们改为pm命令试一下,结果发现成功了!那么现在我们分析一下为什么adb命令会导致出现ANR问题,而pm命令就不会出现错误。乐淘棋牌一个命令的下达,肯定会调用相应的方法去处理,只不过这个调用过程在系统的内部,我们外界是看不到的,只能得到命令执行的结果。就好比我们使用命令去卸载App应用,同样也是在内部调用了卸载方法,那么具体这个方法是什么?在哪里呢?下面我们就去深入的探讨一下。Android系统卸载App应用都是调用了一个类中方法,不管是非静默模式还是静默模式,这个类就是PackageInstaller类。当然Android系统安装App也同样是调用的它里面的方法,这个类功能从它的名字上就可以看出来:打包安装程序。当然这个类我们在平常的开发中是用不到的,同样也是无法调用的,这个类同样也是一个底层调用的类。在这个类中我们可以找到具体的卸载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();

}

}这个是PackageInstaller类中的四个uninstall()方法,具体的功能就是卸载App应用。当然这四个方法用于卸载不同状态的应用,具体的使用请看官方给出的描述文档,这里不再具体的做出分析。现在我们知道了卸载App调用的是PackageInstaller类的uninstall()方法,那么这个和命令的方式有什么关系呢?我们看一下PackageInstaller类的所处路径你就明白了,PackageInstaller类的所处路径为/android/content/pm/PackageInstaller.java,具体在博主这里的完整路径为:很明显,在/pm路径下。pm全称packagemanager,意思包的管理者,pm命令说白了就是包管理命令,进一步说,只有使用pm命令才会调用/pm路径下的底层方法,也就是说才会执行包文件的操作。这下你明白为什么使用adb会导致ANR问题了吧,因为程序找不到执行方法啊!纯真棋牌好了,现在我们解决了最重要的需求,静默卸载App,那么接下来的需求就很简单实现了,批量卸载,批量选择,这里直接使用一个循环不停的执行卸载命令就好了。按照这个思路我们开始写代码。首先是界面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嵌套一个LinearLayout布局来实现App列表,其中单个的App信息使用动态加载的形式添加。下面是一个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="应用包名"android:textcolor="#000000"></textview></checkbox></linearlayout>很简单,两个控件组成,一个ChexBox控件提供勾选,一个TextView用来展示App的标签。638棋牌接下来我们就需要写主活动中的逻辑性操作了:首先贴上我们的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. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论