下载apk的两种方式(无SD卡条件下)

1.首先无SD卡如何存储?
我们将下载的文件放入 /data/data/packageName/files/ 目录下

public class FileUtil {

    public static File getFileHasNoSDCard(Context context, String fileName){
        boolean flag = false;
        /**
         * 返回一个目录 /data/data/packageName/files/
         * 之所以新建一个文件夹存放apk文件,是因为,如果直接新建/data/data/packageName/files/test.apk
         * 可能会出现 open failed: EISDIR (Is a directory)
         */
        File dir = new File(context.getFilesDir() + "/myapk");
        File file = new File(dir, fileName);
        if (!dir.exists()){
            dir.mkdirs();
        }
        file.delete();
        if (!file.exists()){
            try {
                flag = file.createNewFile();
                String command1 = "chmod 775 " + dir.getAbsolutePath();
                String command2 = "chmod 777 " + file.getAbsolutePath();
                Runtime runtime = Runtime.getRuntime();
                runtime.exec("su");
                runtime.exec(command1);
                runtime.exec(command2);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return flag ? file : null;
    }
}

2.下面是下载的2中方式,一种是弹出progressDialog,另一种是notification
第一种:

public class UpdateByProgressDialog {
    private MainActivity instance;
    private ProgressDialog progressDialog;
    private File newFile;
    private String downUrl;
    private String appName;
    public UpdateByProgressDialog(MainActivity instance, String downUrl, String appName){
        this.instance = instance;
        this.downUrl = downUrl;
        this.appName = appName;
    }
    public void downFileByProgressDialog(){
        progressDialog = new ProgressDialog(instance);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        //false 设置进度条进度不确定
        progressDialog.setIndeterminate(false);
        progressDialog.setTitle(instance.getString(R.string.is_downloading));
        progressDialog.setMessage(instance.getString(R.string.please_wait));
        progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.show();
        //启动线程
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();

    }

    class MyRunnable implements Runnable{
        @Override
        public void run() {
            HttpClient httpClient = new DefaultHttpClient();
            HttpGet get = new HttpGet(downUrl);
            HttpResponse response;
            InputStream is = null;
            FileOutputStream fos = null;
            try {
                response = httpClient.execute(get);
                HttpEntity httpEntity = response.getEntity();
                long length = httpEntity.getContentLength();

                if (length == -1 || length == 0){
                    Toast.makeText(instance, "文件不存在", Toast.LENGTH_SHORT).show();
                    return;
                }
                //进度最大值设为100
                progressDialog.setMax(100);
                progressDialog.setProgress(0);
                is = httpEntity.getContent();
                if (is != null){
                    newFile = FileUtil.getFileHasNoSDCard(instance, appName);
                    if (newFile == null){
                        Toast.makeText(instance, "内置SD卡异常", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    fos = new FileOutputStream(newFile);
                    byte[] buffer = new byte[1024];
                    int sum = 0;
                    int count = -1;

                    while ((count = is.read(buffer)) != -1){
                        fos.write(buffer, 0 , count);
                        sum += count;
                        if (length > 0){
                            int progress = (int)(sum * 100 / length);
                            progressDialog.setProgress(progress);
                        }
                    }
                    fos.flush();
                    handler.sendEmptyMessage(0);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            finally {
                if (progressDialog != null && progressDialog.isShowing()){
                    progressDialog.dismiss();
                }
                if (fos != null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (is != null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            //设置最后进度100
            progressDialog.setProgress(100);
            //安装程序
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(newFile), "application/vnd.android.package-archive");
            instance.startActivity(intent);
        }
    };
}

第二种:

public class UpdateByNotificationService extends Service {
    private String appName;
    private String downUrl;
    private File newFile;
    private static final int TIMEOUT = 10 * 1000;
    private NotificationManager notificationManager;
    private Notification notification;
    //remoteView  字面理解远程的视图,描述一个view对象能够显示在其他进程中,可以融合一个layout资源文件实现布局
    private RemoteViews contentView;
    private PendingIntent pendingIntent;
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        appName = intent.getStringExtra("appName");
        downUrl = intent.getStringExtra("downUrl");
        Log.d("appName", appName + downUrl);

        newFile = FileUtil.getFileHasNoSDCard(getApplicationContext(), appName);
        if (newFile != null){
            createNotification();
            //启动下载线程
            new DownloadThread().start();
        }else {
            Toast.makeText(getApplicationContext(), "内置SD卡异常", Toast.LENGTH_SHORT).show();
            stopSelf();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 创建通知
     */
    private void createNotification(){
        notification = new Notification(R.drawable.header, appName + getString(R.string.is_downloading), System.currentTimeMillis());
        notification.flags = Notification.FLAG_ONGOING_EVENT;
        //自定义notification的显示
        contentView = new RemoteViews(getPackageName(), R.layout.notification_item);
        contentView.setTextViewText(R.id.notificationTitle, appName + getString(R.string.is_downloading));
        contentView.setTextViewText(R.id.notificationPercent, "0%");
        contentView.setProgressBar(R.id.notificationProgress, 100, 0, false);
        notification.contentView = contentView;
        notification.contentIntent = pendingIntent;

        notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(R.layout.notification_item, notification);
    }

    private class DownloadThread extends Thread{
        @Override
        public void run() {
            super.run();
            long downloadSize = downloadUpdateFile();
            if (downloadSize > 0){
                mHandler.sendEmptyMessage(0);
            }else {
                mHandler.sendEmptyMessage(1);
            }
        }
    }

    /**
     * 下载更新的文件
     */
    public long downloadUpdateFile(){
        int down_step = 3;//每次更新的进度数
        int total_size = 0;//文件总大小
        int downloadCount = 0;//已经下载好的大小
        int updateCount = 0;//已上传的文件大小
        InputStream is = null;
        FileOutputStream fos = null;
        HttpURLConnection httpURLConnection = null;
        try {
            URL url = new URL(downUrl);
            httpURLConnection = (HttpURLConnection)url.openConnection();
            httpURLConnection.setConnectTimeout(TIMEOUT);
            httpURLConnection.setReadTimeout(TIMEOUT);

            //获取下载文件的size
            total_size = httpURLConnection.getContentLength();
            if (httpURLConnection.getResponseCode() == 404){
                return 0;
            }
            is = httpURLConnection.getInputStream();
            fos = new FileOutputStream(newFile, false);//文件存在则覆盖
            byte[] buffer = new byte[1024];
            int readSize = -1;
//            contentView = new RemoteViews(getPackageName(), R.layout.notification_item);

            while ((readSize = is.read(buffer)) != -1){
                fos.write(buffer, 0 ,readSize);
                downloadCount += readSize;//实时获取下载的大小
                //看着是匀速下载,其实不一定,这里只是超过了才更新它
                if (updateCount == 0 || (downloadCount * 100 / total_size - down_step) >= updateCount){
                    updateCount += down_step;
                    //改变通知栏
                    contentView = new RemoteViews(getPackageName(), R.layout.notification_item);
                    contentView.setTextViewText(R.id.notificationTitle, updateCount + "%");
                    contentView.setTextViewText(R.id.notificationPercent, updateCount + "%");
                    contentView.setProgressBar(R.id.notificationProgress, 100, updateCount, false);
                    notification.contentView = contentView;
                    notification.contentIntent = pendingIntent;
                    notificationManager.notify(R.layout.notification_item, notification);
                }
            }
        }
        catch (MalformedURLException e){
            e.printStackTrace();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        finally {
            if (httpURLConnection != null){
                httpURLConnection.disconnect();
            }
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return downloadCount;
    }
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    Uri uri = Uri.fromFile(newFile);
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setDataAndType(uri, "application/vnd.android.package-archive");
                    //pendingIntent与intent的区别是,pendingIntent的执行不是立刻的,实质是参数传进来的操作
                    //pendingIntent的目的在于它所包含的intent的操作是满足某些条件的,通常用于notification的发送,
                    // 短消息SMSManager的发送和警报器AlarmManager的执行
                    //intent一般是activity,BroadcastReceiver,service之间传递数据,而pendingIntent,一般用在notification上
                    //可以理解为延时的intent,pendingIntent是对Intent的一个包装
                    pendingIntent = PendingIntent.getActivity(UpdateByNotificationService.this, 0, intent, 0);

                    notification.flags = Notification.FLAG_AUTO_CANCEL;
                    notification.setLatestEventInfo(UpdateByNotificationService.this, appName, getString(R.string.download_success), pendingIntent);//点击后将会执行pendingIntent
                    notificationManager.notify(R.layout.notification_item, notification);
                    stopSelf();
                    break;
                case 1:
                    notification.flags = Notification.FLAG_AUTO_CANCEL;
                    notification.setLatestEventInfo(UpdateByNotificationService.this, appName, getString(R.string.download_fail), null);
                    stopSelf();
                    break;
            }
        }
    };
}

下面是MainActivity类

/**
 * 本例是一个下载app的事例
 * 分2中,一种用ProgressDialog进度条,另一种用Notification通知栏
 * 本例着重 在手机无SD卡时候,不得不下载到/data/data/packageName/files/  目录下
 */
public class MainActivity extends Activity implements View.OnClickListener{
    public static final String downUrl = "http://www.apk3.com/uploads/soft/201504/jcjx.045703.apk";
//    public static final String downUrl = "http://down.360safe.com/instmobilemgr.exe";//这不是坑爹吗,有些链接下载下来不能安装,估计是链接问题
    private Button btn_progressDialog, btn_notification;
    private MainActivity instance;
    private static final String appName = "test.apk";
    private UpdateByProgressDialog updateByProgressDialog;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        instance = this;

        btn_progressDialog = (Button)findViewById(R.id.btn_progressDialog);
        btn_notification = (Button)findViewById(R.id.btn_notification);

        btn_progressDialog.setOnClickListener(this);
        btn_notification.setOnClickListener(this);

        updateByProgressDialog = new UpdateByProgressDialog(instance, downUrl, appName);
    }


    @Override
    public void onClick(View view) {
        switch (view.getId()){
            //方法一:弹出progressDialog
            case R.id.btn_progressDialog:
                updateByProgressDialog.downFileByProgressDialog();
                break;
            //方法二:弹出notification
            //方法二的实现在UpdataService.class
            case R.id.btn_notification:
                Intent intent = new Intent(instance, UpdateByNotificationService.class);
                intent.putExtra("appName",appName);
                intent.putExtra("downUrl",downUrl);
                startService(intent);
                break;
        }
    }
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="30sp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="40dp"
        android:text="下载apk的2种方式"/>

    <LinearLayout
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <Button
            android:id="@+id/btn_progressDialog"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:text="方法一"/>

        <Button
            android:id="@+id/btn_notification"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:text="方法二"/>
    </LinearLayout>
</RelativeLayout>

下面是通知的布局文件notification_item.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="30sp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="40dp"
        android:text="下载apk的2种方式"/>

    <LinearLayout
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <Button
            android:id="@+id/btn_progressDialog"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:text="方法一"/>

        <Button
            android:id="@+id/btn_notification"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:text="方法二"/>
    </LinearLayout>
</RelativeLayout>

下面是写的过程中遇到的问题:
java.io.FileNotFoundException: /data/data/com.suhu_tech.downloadapp/files/test.apk: open failed: EISDIR (Is a directory)
原因:直接新建程序会认为是个文件夹而不是个文件,在test.apk上面再加一层即可
参考自:
http://blog.csdn.net/zhufuing/article/details/8666230
http://blog.csdn.net/dalancon/article/details/38111679

代码下载:
http://download.csdn.net/detail/zhiren1992/9132867

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值