Android中下载单个应用的方法

本文记录了在Android项目中实现下载应用的详细过程,包括检查手机中是否存在相同包名的应用,以及如何开始下载操作。代码逻辑较为繁琐,作者计划后期进行优化。

  前一段时间因为公司项目砍掉,导致了一段时间的失业期,赶在年前这么个时间段,迫于无奈之下接了一个外派的项目合同,为期一个月,削微有些蛋疼。这一阵一直在做一些页面布局之类的东西,感觉时间都有点荒废掉了,不过庆幸的是可以参考人家项目中的一些代码。我做的是下载游戏功能的界面,所以顺便参考了一下实现下载逻辑的代码,由于不是自己实现的,逻辑等方面都有些混乱。在此记录一下,旨为加深一下自己的印象,同时留待以后可能用到的时候做一些参考。
  具体的使用情景大概是:
  1.判断当前手机中是否安装有相同包名的应用

private boolean isAppInstalled(Context context, String packagename) {
    PackageInfo packageInfo;
    try {
        packageInfo=context.getPackageManager()
        .getPackageInfo(packagename, 0);
    } catch (NameNotFoundException e) {
        packageInfo = null;
    }
    if (packageInfo == null) {
        //没有安装当前包名的应用
        return false;
    } else {
        //已经安装过当前包名的应用
        return true;
    }
}

2.如果没有安装过该包名的应用,执行以下操作:

     if (!isAppInstalled(context, appInfo.getLatest().getPackageName())) {
     //没有安装过该包名的应用,将下载链接的地址进行分割,最后一个/之后为应用的名称
            String[] strs = appInfo.getLatest().getFid().split("/");
            String downName = strs[strs.length - 1];
            //不明白这里为什么用do while循环做
            do {
            //判断下载文件的目录下,此文件是否可以安装,如果可以则直接进行安装
                if (PackageInfoUtils.checkApkCanInstalled(context, Environment.getExternalStorageDirectory() + DOWNLOAD_PATH + "/" + downName)) {
                    installApk(new File(Environment.getExternalStorageDirectory()
                            + DOWNLOAD_PATH, downName), (TextView) v);
                   //跳出循环
                    break;
                }
                //目录下的文件不能直接进行安装,新建一个file对象
                File file = new File(Environment.getExternalStorageDirectory() + DOWNLOAD_PATH, downName);
                //判断当前网络是否可用,如果不可用则弹出吐司提示
                if (!NetworkStatusHandler.isNetWorkAvaliable(context)) {
                    ToastUtils.showAsNoNetwork(context);
                    return;
                }
                //判断下载地址是否为空
                if (Model.getInstance().isEmpty(appInfo.getLatest().getFid())) {
                    Toast.makeText(context, "下载地址错误", Toast.LENGTH_SHORT).show();
                    return;
                }
                //查询处于下载状态的任务(从数据库中查询处于下载状态的数据,根据数据在下载的辅助线程类中查询任务。。这里表述不清楚。。弄不太清各种标记表示的状态,猜测应该是不让同时下载的任务超过8个吧)
                List<DownloadRequest> idleTask = AppDownloadHelper.getInstance().getDownloadTaskIdle(2);

                if (idleTask.size() >= 8) {
                    Toast.makeText(context, "不能添加更多下载任务", Toast.LENGTH_SHORT).show();
                    return;
                }
                       //所有其他的条件都符合了,开始进行下载了            
                download(appInfo);
            } while (false);
        }

第二步中用到的方法:

        //判断是否可以安装
    public static boolean checkApkCanInstalled(Context context, String filePath) {
    PackageInfo info = getUninstallApkInfo(context, filePath);
    return info != null ? true : false;
}
       public static PackageInfo getUninstallApkInfo(Context context, String filePath) {
    File f = new File(filePath);
    if (!f.exists()) {
        return null;
    }
    PackageInfo info = null;
    try {
        PackageManager pm = context.getPackageManager();
        info = pm.getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return info;
}
    //安装apk文件
     private void installApk(File file, TextView downButton) {
    Intent i = new Intent(Intent.ACTION_VIEW);
        i.setDataAndType(Uri.fromFile(file),
            "application/vnd.android.package-archive");
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    AppStoreInit.getContext().startActivity(i);
}

                // 判断是否有可用的网络连接
public static final boolean isNetWorkAvaliable(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivityManager == null) {
        return false;
    } else {
        NetworkInfo[] info = connectivityManager.getAllNetworkInfo();
        if (info == null) {
            return false;
        } else {
            for (NetworkInfo nf : info) {
                if (nf.getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
            return false;
        }
    }
}

3.开始执行下载的操作了,具体看代码吧

        //括号内的参数表示需要下载的应用的一些信息,这些信息是从后台接口中获取的,包括名称、大小、链接等等。
    private void download(final AppInfo info) {
    //这里是app的下载地址
    final String downloadUrl = info.getLatest().getFid();
    //将Appinfo对象中的信息封装到另一个对象downloadInfo中
    DownloadInfo downloadInfo = getDownloadInfo(info);
    int currentDownType = info.getCurrentDownType();
    //根据当前应用的下载状态进行判断
    if (currentDownType == AppInfo.DOWNLOAD_START) {
        currentDownType = AppInfo.DOWNLOAD_PAUSE;
        info.setCurrentDownType(currentDownType);
        downloadInfo.setBtnCurrentDownType(info.getCurrentDownType());
        //开始下载应用
        AppDownloadHelper.getInstance().downApp(downloadInfo);
    } else if (currentDownType == AppInfo.DOWNLOAD_PAUSE) {
        currentDownType = AppInfo.DOWNLOAD_START;
        info.setCurrentDownType(currentDownType);
        downloadInfo.setBtnCurrentDownType(info.getCurrentDownType());
        //暂停正在下载的应用
        AppDownloadHelper.getInstance().pause(downloadInfo);
    }

}

        //根据AppInfo的信息得到DownloadInfo的对象
     private DownloadInfo getDownloadInfo(AppInfo appInfo) {

    final String downloadName = appInfo.getName();
    final String downloadUrl = appInfo.getLatest().getFid();
    final String fileExtensions = appInfo.getFileExtensions();
    final int installationDirectory = appInfo.getInstallationDirectory();
    final int sizeLong = appInfo.getLatest().getSizeLong();
    final int position = appInfo.getPosition();
    int currentDownType = appInfo.getCurrentDownType();
    final String appId = appInfo.getId();
    DownloadInfo downloadInfo = new DownloadInfo();
    downloadInfo.setDownloadName(downloadName);
    downloadInfo.setDownloadUrl(downloadUrl);

    downloadInfo.setFileExtensions(fileExtensions);
    downloadInfo.setDownloadFileSize(sizeLong);
    downloadInfo.setInstallationDirectory(installationDirectory);

    downloadInfo.setPosterfid(appInfo.getIconfid());
    downloadInfo.setSubhead(appInfo.getSubhead());
    com.dfsj.video.download.beans.AppInfo downAppInfo = new com.dfsj.video.download.beans.AppInfo();
    downAppInfo.setName(appInfo.getName());
    AppLatestInfo appLatestInfo = new AppLatestInfo();
    appLatestInfo.setFid(appInfo.getLatest().getFid());
    appLatestInfo.setPackageName(appInfo.getLatest().getPackageName());
    appLatestInfo.setSize(appInfo.getLatest().getSize());
    appLatestInfo.setVersionCode(appInfo.getLatest().getVersionCode());
    appLatestInfo.setVersionName(appInfo.getLatest().getVersionName());
    downAppInfo.setLatest(appLatestInfo);
    downAppInfo.setScore(appInfo.getScore());
    downAppInfo.setOnedescription(appInfo.getOnedescription());
    downAppInfo.setGametype(appInfo.getGametype());

    downloadInfo.setInfo(downAppInfo);
    downloadInfo.setDownloadTpye(2);
    downloadInfo.setAppId(Integer.valueOf(appInfo.getId()));

    downloadInfo.setDownloadHelperListener(this);
    downloadInfo.setDetailDownloadHelperListener(this);

    return downloadInfo;
}

4.开始下载。。。。(感觉已经开始过好几次了。。。囧。。。。),还是上代码吧。。。

          public void downApp(DownloadInfo downloadInfo) {
    if (SystemUtils.getNetType(DownloadInit.getContext()) != 4) {
        ToastUtils.showShort(DownloadInit.getContext(), "当前为运营商网络,继续下载会产生流量费用");
    }
    String downloadUrl = downloadInfo.getDownloadUrl();
    String downloadName = downloadInfo.getDownloadName();
    View view = downloadInfo.getUpdateView();
    //一些下载过程中状态的监听,包括进度条的更新,下载过程中错误的回调等等
    downloadHelperListener = downloadInfo.getDownloadHelperListener();
    detailDownloadHelperListener = downloadInfo.getDetailDownloadHelperListener();
    String[] strs = downloadUrl.split("/");
    String downName = strs[strs.length - 1];
    File file = new File(DOWNLOAD_PATH, downName);

   //这几步应该是得到一个用来下载的请求
    DownloadRequest request = queryDownloadInfo(downloadUrl);

    if (null == request) {
        request = new DownloadRequest(downloadUrl,
                file.getAbsolutePath(), 0);
    }
    if (null != view)
        request.setView(view);
    request.setExtraValue(downloadInfo.getPosterfid());
    request.setFileExtensions(downloadInfo.getFileExtensions());
    request.setDownloadFileSize(downloadInfo.getDownloadFileSize());
    request.setInstallationDirectory(downloadInfo.getInstallationDirectory());
    request.setTitle(downloadName);
    request.setInfo(downloadInfo.getInfo());
    request.setBtnCurrentDownType(downloadInfo.getBtnCurrentDownType());
    request.setDownloadTpye(downloadInfo.getDownloadTpye());
    request.setDownloadEpisode(downloadInfo.getSubhead());
    request.setAppId(downloadInfo.getAppId());
    request.setPackageName(downloadInfo.getInfo().getLatest().getPackageName());
    request.setScore(downloadInfo.getInfo().getScore());
    request.setOnewordDesc(downloadInfo.getInfo().getOnedescription());
    request.setGametype(downloadInfo.getInfo().getGametype());
    //这个方法是真正的执行下载任务的
    mDownloadManager.enqueue(request);
    setClickStatus(request);
}

5.感觉这个代码写的确实是挺啰嗦的,希望有机会的话可以自己精简一下。。。。太蛋疼了。。

     public void enqueue(DownloadRequest request) {
           VolumeSize compare = new VolumeSize();
    if (request.getSrcUri() == null)
        return;
    int type = request.getmType();
    if (type == 1) {
        if (null != request.getDestUri())
            request.setDestUri(request.getDestUri());
        request.setmTimeStamp(System.currentTimeMillis());
        request.setDownloadStatus(DownloadColumns.STATUS_IDLE);
        //这里是进行开始下载任务。。感觉要吐血了。。
        mDownloadThreadPool.enqueue(request);
    } else {
        boolean has = mDBHelper.isHasFile(request.getmUniquely_id());

        if (request.getId() == -1 || has == true) {

            long id = mDBHelper.insert(request.toContentValues());
            request.setId(id);
            request.setDownloadSize(0);
        }
        request.setmTimeStamp(System.currentTimeMillis());
        request.setDownloadStatus(DownloadColumns.STATUS_IDLE);
        if (!TextUtils.isEmpty(request.getDestUri())) {
            request.setDestUri(request.getDestUri());
        } else {
            String path = SharePrefUtils.getString("PATH", Environment.getExternalStorageDirectory().getAbsolutePath());
            String url = path + DOWNLOAD_PATH + "/" + request.getTitle();
            request.setDestUri(url);
        }
        Log.d(TAG, "enqueue: " + request.getDownloadStatus() + "type" + request.getSrcUri());
        mDownloadThreadPool.enqueue(request);
        String where = DownloadColumns._ID + "=" + request.getId();
        mDBHelper.update(request.toContentValues(), where, null);
    }
}
    private ExecutorService mThreadPool;
    //执行下载任务了。。。。。
    void enqueue(DownloadRequest request) {
    Log.d(TAG, "enqueue: ");
    //这里是一个开启线程池的对象(DownloadTask见下面。。。)
    mThreadPool.submit(new DownloadTask(request));
    Log.d(TAG, "enqueue: submit");
    mDownloadRequests.add(request);

}

      class DownloadTask implements Runnable {

    private DownloadRequest mDownloadRequest;

    DownloadTask(DownloadRequest request) {
        mDownloadRequest = request;
        Log.d(TAG, "DownloadTask: ");
    }

    @Override
    public void run() {
        Log.d(TAG, "run: ");
        int statusCode = -1;
        if (mDownloadRequest.getDownloadStatus().equals(DownloadColumns.STATUS_IDLE)) {
            //开始下载。。。。。
            statusCode = mHttpDownloader.doDownload(mDownloadRequest);
        }
        mDownloadRequests.remove(mDownloadRequest);
    }
}

    //执行下载操作的代码(应该是包含了断点续传的)
     public int doDownload(DownloadRequest request) {
    Log.d(TAG, "doDownload: start" + request.getDownloadStatus());
    // 不能设置成全局变量,会导致写文件出错
    HttpURLConnection conn = null;
    InputStream inStream = null;
    RandomAccessFile oSavedFile = null;
    long breakPoint = 0L;
    File destFile = null;
    int statusCode = 0;
    try {
        URL url = new URL(request.getSrcUri());
        conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5 * 1000);
        conn.setReadTimeout(10 * 1000);
        conn.setRequestMethod("GET");
    } catch (IOException e) {
        saveDownloadRequest(request, ErrorCode.HTTP_URL_CONNECTION_ERROR, "HttpURLConnection出错,e:" + e);
        notifyError(request);
        conn.disconnect();
        return statusCode;
    }
    conn.setRequestProperty(
            "Accept",
            "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
    conn.setRequestProperty("Accept-Language", "zh-CN");
    conn.setRequestProperty("Referer", request.getSrcUri());
    conn.setRequestProperty("Charset", "UTF-8");
    // 在conn.connect();之前new os 不然会导致暂停后无法重新下载
    destFile = setupFile(request.getDestUri() + TEMP_SUFFIX);
    // 如果下载文件存在
    if (destFile.exists() && destFile.isFile() && destFile.length() > 0) {
        breakPoint = destFile.length();
        request.setDownloadSize(breakPoint);
    } else {
        request.setDownloadSize(0);
    }
    conn.setRequestProperty("Range", "bytes=" + breakPoint + "-");
    conn.setRequestProperty(
            "User-Agent",
            "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
    conn.setRequestProperty("Connection", "Keep-Alive");
    conn.setRequestProperty("content-type", "text/html");
    int responseCode = -1;
    try {
        conn.connect();
        responseCode = conn.getResponseCode();
    } catch (IOException e) {
        saveDownloadRequest(request, ErrorCode.HTTP_URL_CONNECTION_CONNECT_ERROR, "HttpURLConnection connect出错,e:" + e);
        notifyError(request);
        conn.disconnect();
        return statusCode;
    }
    if (responseCode == 206) {
        Log.d(TAG, "doDownload: " + responseCode);
        try {
            inStream = conn.getInputStream();
        } catch (IOException e) {
            saveDownloadRequest(request, ErrorCode.HTTP_URL_CONNECTION_GET_INPUTSTREAM_ERROR, "HttpURLConnection getInputStream出错,e:" + e + ",responseCode:" + responseCode);
            notifyError(request);
            closeHttpConnection(inStream, conn, oSavedFile);
            return responseCode;
        }
        try {
            oSavedFile = new RandomAccessFile(destFile, "rw");
        } catch (FileNotFoundException e) {
            saveDownloadRequest(request, ErrorCode.FILE_OUT_PUT_STREAM_WITH_RANGE_ERROR, "RandomAccessFile出错,e:" + e);
            notifyError(request);
            closeHttpConnection(inStream, conn, oSavedFile);
            return statusCode;
        }
        try {
            oSavedFile.seek(breakPoint);
        } catch (IOException e) {
            saveDownloadRequest(request, ErrorCode.FILE_OUT_PUT_STREAM_WITH_RANGE_ERROR, "RandomAccessFile seek出错,e:" + e);
            notifyError(request);
            closeHttpConnection(inStream, conn, oSavedFile);
            return statusCode;
        }
        try {
            long filesize = conn.getContentLength();
            if (request.getDownloadSize() == 0) {
                request.setTotalSize(filesize);
            }
            byte buffer[] = new byte[800096];
            int length = 0;
            notifyStart(request);
            startTime = System.currentTimeMillis();
            while (request.getDownloadStatus().equals(
                    DownloadColumns.STATUS_START)
                    && (length = inStream
                    .read(buffer, 0, buffer.length)) != -1) {
                oSavedFile.write(buffer, 0, length);
                long downloadSize = request.getDownloadSize();
                downloadSize += length;
                request.setDownloadSize(downloadSize);
                long mdownloadsize = request.getMtemdownsize();// 获取临时下载数量
                mdownloadsize += length;
                request.setMtemdownsize(mdownloadsize);
                curTime = System.currentTimeMillis();
                usedTime = (int) ((curTime - startTime) / 1000);
                if (usedTime == 0)
                    usedTime = 1;
                downloadSpeed = (int) ((mdownloadsize / usedTime) / 1024);
                request.setDownloadSpeed(downloadSpeed);
                notifyProgress(request);
                // 获取到停止状态跳出循环
                if (request.getDownloadStatus().equals(
                        DownloadColumns.STATUS_PAUSE)) {
                    break;
                }
            }
            request.setMtemdownsize(0);
            request.setDownloadSpeed(0);
            if (request.getTotalSize() == request.getDownloadSize()
                    && !(request.getDownloadStatus()
                    .equals(DownloadColumns.STATUS_COMPLETE))) {
                destFile.renameTo(new File(request.getDestUri()));
                request.setDownloadStatus(DownloadColumns.STATUS_COMPLETE);
                request.setMlastTimeStamp(System.currentTimeMillis());
                request.setDownloadSize(0L);
                notifyComplete(request);
            } else {
                notifyProgress(request);
            }
        } catch (IOException e) {
            saveDownloadRequest(request, ErrorCode.IO_ERROR, "Os write 错误,e:" + e + "ResponseCode:" + responseCode);
            notifyError(request);
        } finally {
            closeHttpConnection(inStream, conn, oSavedFile);
        }
    } else {
        saveDownloadRequest(request, ErrorCode.HTTP_RESPONSE_CODE_ERROR, "ResponseCode不等于206,ResponseCode:" + responseCode);
        notifyError(request);
        closeHttpConnection(inStream, conn, oSavedFile);
    }
    return statusCode;
}

结语,我反正是累的吐血了,感觉代码的逻辑太啰嗦,比想象中复杂了一万倍,后期有时间的话再优化一次,今天就到这。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值