安装应用android批量安装APK
今天个人几篇文章介绍了改安装应用的文章. 关联文章的地址
在android机上安装APK时一般都是借助PC端的91手机助手或者豌豆荚之类的工具;或者直接将APK下载到android机子上手动点击安装,手动安装时系统会弹出“是不是要安装该应用程序?”的对话框让你选择是不是安装,如果一次只安装一两个APK还可以在每次弹出对话框时选择“安装“,如果一次须要安装数十个时这是相称费劲而且容易遗漏APK没有安装的。
能不能自己写个应用来实现一次批量安装全部APK呢?谜底是肯定的,但是对于一个只熟悉android应用开发的人员是办不到的。因为google为了避免出于一些特殊目的的开发人员编写应用程序偷偷的在你的android机子上安装一些有特殊目的的APK,已将静默安装APK的API屏蔽了,在官方发布的SDK中是没有这样的API给你调用的。但是对于系统开发人员还是很容易开收回这样的应用的,因为我们可以在编译系统时去编译我们调用了google隐藏了的API的应用。
先上个我写的批量安装APK应用的界面和批量安装APK时的效果图,该应用实现的功能是先扫描外置SD、TF卡下的全部APK,点击”安装APK“按钮后即开始一次批量安装完扫描到的APK,不须要用户去干预。
该应用重要用到的是android.content.pm.PackageManager类下的installPackage方法来实现静默安装全部APK的。
工程文件列表:
updatepackage │ .classpath │ .project │ Android.mk │ AndroidManifest.xml │ MainActivity.apk │ ├─res │ ├─drawable │ │ back.jpg │ │ │ ├─drawable-hdpi │ │ ic_action_search.png │ │ ic_launcher.png │ │ │ ├─drawable-ldpi │ │ ic_launcher.png │ │ │ ├─drawable-mdpi │ │ ic_action_search.png │ │ ic_launcher.png │ │ │ ├─drawable-xhdpi │ │ ic_action_search.png │ │ ic_launcher.png │ │ │ ├─layout │ │ activity_main.xml │ │ │ ├─menu │ │ activity_main.xml │ │ │ ├─values │ │ dimens.xml │ │ strings.xml │ │ styles.xml │ │ │ └─values-large │ dimens.xml │ └─src └─com └─example └─adnroid └─updatepackage ApkFile.java ApkSearchUtils.java MainActivity.java UpdateBroadcastReceiver.java
android系统源代码下添加我们的updatepackage工程,工程下添加用于编译的Android.mk文件内容如下所示:
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := MainActivity LOCAL_DEX_PREOPT :=false LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE)
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="@string/textview1text"/> <ProgressBar android:id="@+id/progressBar1" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text= "@string/textview2text"/> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="@string/button1text"/> </LinearLayout>
AndroidManifest.xml文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.adnroid.updatepackage" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.adnroid.updatepackage.MainActivity" android:label="@string/title_activity_main" android:launchMode="singleTask"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name="UpdateBroadcastReceiver" android:enabled="true"> <intent-filter > <action android:name="com.example.adnroid.updatepackage.hello"/> </intent-filter> </receiver> </application> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PHONESTATE" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> <uses-permission android:name="android.permission.CLEAR_APP_CACHE" /> <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /> </manifest>
重要界面MainActivity.java代码:
package com.example.adnroid.updatepackage; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.content.Intent; import android.net.Uri; import java.io.File; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.IPackageInstallObserver; public class MainActivity extends Activity { int count,i; ApkSearchUtils apksearchutils; private static final int UPDATE = 0; ProgressBar progressbar1; Button button1; TextView textview1; TextView textview2; private final int INSTALL_COMPLETE = 1; boolean threadrun=true; boolean installcomplete=false; private final int INSTALL_COMPLETED = 1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button1=(Button)findViewById(R.id.button1); progressbar1=(ProgressBar)findViewById(R.id.progressBar1); textview1=(TextView)findViewById(R.id.textView1); textview2=(TextView)findViewById(R.id.textView2); progressbar1.setMax(100); apksearchutils=new ApkSearchUtils(this); apksearchutils.FindAllAPKFile(new File("/mnt/sdcard/")); count=apksearchutils.getMyFiles().size(); i=0; Log.e("zkliu","count:"+String.valueOf(count)+","+"i:"+String.valueOf(i)); button1.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View arg0) { new Thread(new Runnable() { @Override public void run() { threadrun=true; installcomplete=true; while(threadrun){ try{ if(!installcomplete){ Thread.sleep(10); } else{ installcomplete=false; Message msg=new Message(); msg.what=UPDATE; myhandler.sendMessage(msg); } }catch(Exception e){ e.printStackTrace(); } } button1.setEnabled(true); } }).start(); } }); } Handler myhandler=new Handler(){ public void handleMessage(android.os.Message msg) { switch(msg.what){ case UPDATE: if(i<count){ button1.setEnabled(false); progressbar1.setProgress((int)((double)(i+1)/(double)count*100)); textview1.setText("安装进度:"+String.valueOf((int)((double)(i+1)/(double)count*100))+"%"); textview2.setText("当前安装文件为:"+apksearchutils.getMyFiles().get(i).getFilePath()); Log.e("zkliu",R.string.textview2text+apksearchutils.getMyFiles().get(i).getFilePath()); Uri uri = Uri.fromFile(new File(apksearchutils.getMyFiles().get(i).getFilePath())); int installFlags = 0; PackageManager pm = getPackageManager(); try { PackageInfo pi = pm.getPackageInfo(apksearchutils.getMyFiles().get(i).getPackageName(),PackageManager.GET_UNINSTALLED_PACKAGES); if(pi != null) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; } } catch (NameNotFoundException e) { } PackageInstallObserver observer = new PackageInstallObserver(); pm.installPackage(uri, observer, installFlags,apksearchutils.getMyFiles().get(i).getPackageName()); i++; } else{ threadrun=false; button1.setEnabled(true); } break; case INSTALL_COMPLETED: installcomplete=true; break; } } }; class PackageInstallObserver extends IPackageInstallObserver.Stub { public void packageInstalled(String packageName, int returnCode) { Message msg = myhandler.obtainMessage(INSTALL_COMPLETED); msg.arg1 = returnCode; myhandler.sendMessage(msg); } }; @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
在编译android系统时编译该应用的指令如下所示:
root@l-desktop:~/A13/android4.0# source build/envsetup.sh including device/samsung/maguro/vendorsetup.sh including device/samsung/tuna/vendorsetup.sh including device/softwinner/common/vendorsetup.sh including device/softwinner/nuclear-evb_mmc/vendorsetup.sh including device/softwinner/nuclear-evb/vendorsetup.sh including device/softwinner/nuclear-mini/vendorsetup.sh including device/ti/panda/vendorsetup.sh including sdk/bash_completion/adb.bash root@l-desktop:~/A13/android4.0# cd device/softwinner/common/packages/updatepackage/ root@l-desktop:~/A13/android4.0/device/softwinner/common/packages/updatepackage# mmm ./ find: `device/softwinner/nuclear-evb/apkwithlib': 没有那个文件或目录 find: `device/softwinner/nuclear-evb/apkwithlib/lib': 没有那个文件或目录 ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=4.0.4 TARGET_PRODUCT=full TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a HOST_ARCH=x86 HOST_OS=linux HOST_BUILD_TYPE=release BUILD_ID=IMM76D ============================================ make:进入目录'/root/A13/android4.0' target R.java/Manifest.java: MainActivity (out/target/common/obj/APPS/MainActivity_intermediates/src/R.stamp) Warning: AndroidManifest.xml already defines versionCode (in http://schemas.android.com/apk/res/android); using existing value in manifest. Warning: AndroidManifest.xml already defines versionName (in http://schemas.android.com/apk/res/android); using existing value in manifest. Warning: AndroidManifest.xml already defines minSdkVersion (in http://schemas.android.com/apk/res/android); using existing value in manifest. Warning: AndroidManifest.xml already defines targetSdkVersion (in http://schemas.android.com/apk/res/android); using existing value in manifest. target Java: MainActivity (out/target/common/obj/APPS/MainActivity_intermediates/classes) Copying: out/target/common/obj/APPS/MainActivity_intermediates/classes-jarjar.jar Copying: out/target/common/obj/APPS/MainActivity_intermediates/emma_out/lib/classes-jarjar.jar Copying: out/target/common/obj/APPS/MainActivity_intermediates/classes.jar Copying: out/target/common/obj/APPS/MainActivity_intermediates/noproguard.classes.jar target Dex: MainActivity Copying: out/target/common/obj/APPS/MainActivity_intermediates/noproguard.classes.dex target Package: MainActivity (out/target/product/generic/obj/APPS/MainActivity_intermediates/package.apk) Warning: AndroidManifest.xml already defines versionCode (in http://schemas.android.com/apk/res/android); using existing value in manifest. Warning: AndroidManifest.xml already defines versionName (in http://schemas.android.com/apk/res/android); using existing value in manifest. Warning: AndroidManifest.xml already defines minSdkVersion (in http://schemas.android.com/apk/res/android); using existing value in manifest. Warning: AndroidManifest.xml already defines targetSdkVersion (in http://schemas.android.com/apk/res/android); using existing value in manifest. 'out/target/common/obj/APPS/MainActivity_intermediates/classes.dex' as 'classes.dex'... Install: out/target/product/generic/system/app/MainActivity.apk make:离开目录“/root/A13/android4.0”
如果须要完整工程,可以发邮件到:229425962@qq.com索取。
文章结束给大家分享下程序员的一些笑话语录:
话剧:程序员过沟
本剧内容纯属虚构,如有雷同……HEHE……俺也没办法了。
话说某市街道改建,某某软件公司门口横七竖八挖了几条大沟。一群程序员(SDK程序员赵某,VB程序员钱某,VC程序员孙某,DELPHI程序员李某)下班从公司里出来,看到门前的几条沟,于是各显神通……门前第一条沟也就半米来宽,SDK程序员赵某二话没说,轻轻一跃跳了过去,看到其它人纷纷把随身携带的公文包(类库)横在沟上踩着过沟,不屑地说,这么小一条沟,犯得着小题大做用那个吗?看我多么轻松多么洒脱多么……多么……(众人皆怒目横视之……)
接着第二条沟有点宽度。SDK程序员赵某还是还是一马当先,飞跃而起……不好,还差一点才到……幸好凭着多年的(跳远?编程?)经验,单手抓住沟沿,颤巍巍地爬了上来,嘴里还念念有词“高手就是高手啊,虽然差一点就……不过毕竟……HEHE……跳远是过沟的基础嘛,有基础(SDK)就有一切的说……”(众人作瞠目结舌状……)看到别人跳过去了,可自己又跳不了那么远,只好再想办法了……VB程序员钱某,DELPHI程序员李某打开手提,连上手机,开始上网找可供过沟的控件……VC程序员孙某却不慌不忙,打开公文包,把几块衬板拆了下来,然后三下五除二拼成一个简易木桥……“虽然这几个板子(类)做得不怎么样,不过先把这个项目应付过去,有时间我自己做一个好了……”于是踩着板子过了沟。
这时钱某和李某也分别找到了合适的东东。钱某找到的是“钢丝绳.ocx”,安装简单,使用方便,拉出一头,对孙某说“大虾,顺手拉兄弟一把……”,于是把绳子系在沟两边的绿化树木上,踩着钢丝就过了沟。刚刚站稳就四方作揖,“小生这里有礼了”。这时一戴着黄袖圈的老太太跳了出来,抓住钱某,“破坏绿化树木,罚款XXXX元,交钱,交钱,交钱!”(老人家作双枪老太婆怒视伪军状
……钱某被逼无奈,只好边掏钱,边对着后台叫道“导演,我这可是因公牺牲,不给个烈士称号也得报销”,后台一个臭鸡蛋飞出,“叫什么叫,我这个月的粮饷还不知哪里去领呢,都什么时代了,你不下岗都不错了……”)
李某看着刚刚好不容易从台湾拖回来的“铝条.ZIP”
--------------------------------- 原创文章 By 安装和应用 ---------------------------------