android批量安装APK

来源:互联网 发布:总体战知乎 编辑:程序博客网 时间:2024/06/03 08:40

    在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 := optionalLOCAL_SRC_FILES := $(call all-subdir-java-files)LOCAL_PACKAGE_NAME := MainActivityLOCAL_DEX_PREOPT :=falseLOCAL_CERTIFICATE := platforminclude $(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() {@Overridepublic void onClick(View arg0) {        new Thread(new Runnable() {        @Overridepublic 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.shincluding device/samsung/maguro/vendorsetup.shincluding device/samsung/tuna/vendorsetup.shincluding device/softwinner/common/vendorsetup.shincluding device/softwinner/nuclear-evb_mmc/vendorsetup.shincluding device/softwinner/nuclear-evb/vendorsetup.shincluding device/softwinner/nuclear-mini/vendorsetup.shincluding device/ti/panda/vendorsetup.shincluding sdk/bash_completion/adb.bashroot@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=RELPLATFORM_VERSION=4.0.4TARGET_PRODUCT=fullTARGET_BUILD_VARIANT=engTARGET_BUILD_TYPE=releaseTARGET_BUILD_APPS=TARGET_ARCH=armTARGET_ARCH_VARIANT=armv7-aHOST_ARCH=x86HOST_OS=linuxHOST_BUILD_TYPE=releaseBUILD_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.jarCopying: out/target/common/obj/APPS/MainActivity_intermediates/emma_out/lib/classes-jarjar.jarCopying: out/target/common/obj/APPS/MainActivity_intermediates/classes.jarCopying: out/target/common/obj/APPS/MainActivity_intermediates/noproguard.classes.jartarget Dex: MainActivityCopying: out/target/common/obj/APPS/MainActivity_intermediates/noproguard.classes.dextarget 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.apkmake:离开目录“/root/A13/android4.0”

    如果需要完整工程,可以发邮件到:229425962@qq.com索取。

 

 

原创粉丝点击