美文网首页
app升级安装

app升级安装

作者: 名字不想带英文 | 来源:发表于2019-10-15 11:31 被阅读0次

    android7.0后文件的访问权限提高了,不能直接使用file://的方式来共享文件了,应该使用
    content://URI的方式来共享文件,并使用FileProvider类来授权。
    先在AndroidManifest.xml添加权限

    <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    

    首先新建在xml文件夹下新建一个文件,名字随意,我这边新建为file_paths.xml。里面这样写道

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <files-path
            name="files"
            path="/" />
        <cache-path
            name="cache"
            path="/" />
        <external-path
            name="external"
            path="/" />
        <external-files-path
            name="external_file_path"
            path="/" />
        <external-cache-path
            name="external_cache_path"
            path="/" />
    
        <!--<external-media-path
            name="external-media-path"
            path=""/>-->
    
    <!--
        files-path:          该方式提供在应用的内部存储区的文件/子目录的文件。
                              它对应Context.getFilesDir返回的路径:eg:”/data/data/com.jph.simple/files”。
    
        cache-path:          该方式提供在应用的内部存储区的缓存子目录的文件。
                              它对应getCacheDir返回的路径:eg:“/data/data/com.jph.simple/cache”;
    
        external-path:       该方式提供在外部存储区域根目录下的文件。
                              它对应Environment.getExternalStorageDirectory返回的路径:
    
        external-cache-path: 该方式提供在应用的外部存储区根目录的下的文件。
                              它对应Context#getExternalFilesDir(String) Context.getExternalFilesDir(null)
                              返回的路径。eg:”/storage/emulated/0/Android/data/com.jph.simple/files”
        -->
    
    </paths>
    

    如果我下载的文件放在getFilesDir里,就用cache-path就行。 其中 name="cache"的cache是别名,可以随便自定义的,而path="/" 里的/则表示 允许访问getFilesDir下所有文件。这上面基本所有路径访问全加上去,反正也没什么不好的。接下来就在AndroidManifest.xml的添加application里添加如下内容

    <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="${applicationId}.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths" />
            </provider>
    androidx的话换成"androidx.core.content.FileProvider"
    

    其中${applicationId}是你app的包名id,android:resource="@xml/file_paths"中的file_paths是你刚才在xml文件夹下新建的文件。
    接下来是获取uri

     public static Uri getUri(Context context, File file) {
            Uri uri;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//大于7.0时
                uri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
                //context.getPackageName() + ".provider"就是你刚才加到AndroidManifest.xml文件里的provider里的android:authorities的值
            } else {
                uri = Uri.fromFile(file);
            }
            return uri;
        }
    

    不单单app升级安装,以后所有用到uri的地方以后都可以用getUri(Context context, File file) 获取到授权的正确的Uri。最后贴下app下载完后制动弹出安装的代码

    private void isAPK(String filePath) {//filePath:安装包的本地地址链接
            File file = new File(filePath);
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//重要,不然安装成功后第一次打开会崩溃
    
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    // 7.0 以上
                    Uri apkUri = ContentUriUtil.getUri(activity, file);
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
                } else {
                    // 7.0以下
                    Uri uri = Uri.fromFile(file);
                    intent.setDataAndType(uri, "application/vnd.android.package-archive");
                }
                activity.startActivity(intent);
        }
    

    题外话,implementation 'com.liulishuo.filedownloader:library:1.6.8',一个挺好用的下载框架
    本文参考:https://blog.csdn.net/MingHuang2017/article/details/82830727
    用上述框架做的android升级的Helper

    import android.app.Activity;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Environment;
    import android.support.v7.app.AlertDialog;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.eluton.base.BaseApplication;
    import com.eluton.bean.gson.UpdateGsonBean;
    import com.eluton.url.Api;
    import com.eluton.url.OkhttpUtil;
    import com.eluton.util.ContentUriUtil;
    import com.eluton.util.LogUtil;
    import com.eluton.yltdemo.R;
    import com.liulishuo.filedownloader.BaseDownloadTask;
    import com.liulishuo.filedownloader.FileDownloadLargeFileListener;
    import com.liulishuo.filedownloader.FileDownloadSampleListener;
    import com.liulishuo.filedownloader.FileDownloader;
    
    import java.io.File;
    
    public class UpdateHelper {
    
        private Activity activity;
        private String downUrl;
        private final String downPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download/开课通.apk";
    
        public UpdateHelper(Activity activity) {
            this.activity = activity;
        }
    
        private AlertDialog updateDialog;
        private TextView wantTv;
    
        private void showUpdate() {
            if (updateDialog == null) {
                AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.AlertDialog);
                View view = LayoutInflater.from(activity).inflate(R.layout.dialog_update, null);
                TextView ensure = view.findViewById(R.id.ensure);
                TextView cancel = view.findViewById(R.id.cancel);
                ImageView warnImg = view.findViewById(R.id.img);
                wantTv = view.findViewById(R.id.notice);
                if (updateGsonBean != null)
                    wantTv.setText("新版本:" + updateGsonBean.getAndroidVersionName());
                cancel.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        if (updateDialog != null)
                            updateDialog.dismiss();
                        if (TaskId != 0) {
                            FileDownloader.getImpl().pause(TaskId);
                        }
                    }
                });
                ensure.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        updateApk();
                    }
                });
                builder.setView(view);
                builder.setCancelable(false);
                updateDialog = builder.create();
            }
            if (!updateDialog.isShowing())
                updateDialog.show();
        }
    
        private UpdateGsonBean updateGsonBean;
    
        public void checkUpdate(final boolean needTip) {
            new Api() {
                @Override
                public void bindView(OkhttpUtil.HttpBean httpBean, boolean state) {
                    if (state && httpBean.getCode() == 200) {
                        updateGsonBean = BaseApplication.gson.fromJson(httpBean.getContent(), UpdateGsonBean.class);
                        if (Integer.parseInt(updateGsonBean.getAndroidVersion()) > BaseApplication.versionCodes) {//BaseApplication.versionCodes
                            downUrl = updateGsonBean.getAndroidDownload();
                            LogUtil.i("url:" + downUrl);
                            showUpdate();
                        } else {
                            if (needTip)
                                Toast.makeText(activity, "当前已经是最新版本", Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        if (needTip)
                            Toast.makeText(activity, httpBean.getContent() + "", Toast.LENGTH_SHORT).show();
                    }
                }
            }.Update();
        }
    
        private int TaskId;
        private boolean isUpdate;//第一次更新时删掉旧安装包的标志符,保证下载最新的安装包
    
        private void updateApk() {
            if (!isUpdate) {
                isUpdate = true;
                File file = new File(downPath);
                if (file.exists()) {
                    file.delete();
                }
            }
            BaseDownloadTask task = FileDownloader.getImpl().create(downUrl).setPath(downPath).setListener(new FileDownloadSampleListener() {
                @Override
                protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {
                    int num = (int) (soFarBytes * 100 / totalBytes);
                    wantTv.setText("下载进度:" + num + "%");
                }
    
                @Override
                protected void error(BaseDownloadTask task, Throwable e) {
                    Toast.makeText(activity, e.getMessage() + "", Toast.LENGTH_SHORT).show();
                }
    
                @Override
                protected void completed(BaseDownloadTask task) {
                    wantTv.setText("下载完成");
                    installApk();
                }
            });
            TaskId = task.getId();
            task.start();
        }
    
        private void installApk() {
            File file = new File(downPath);
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//重要,不然安装成功后第一次打开会崩溃
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                // 7.0 以上
                Uri apkUri = ContentUriUtil.getUri(activity, file);//
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
            } else {
                // 7.0以下
                Uri uri = Uri.fromFile(file);
                intent.setDataAndType(uri, "application/vnd.android.package-archive");
            }
            activity.startActivity(intent);
        }
    }
    

    其中自定义了对话框,R.style.AlertDialog和xml视图的内容如下

    <style name="AlertDialog" parent="android:style/Theme.Dialog">
            <item name="android:background">@android:color/transparent</item>
            <item name="android:windowBackground">@android:color/transparent</item>
            <item name="android:windowNoTitle">true</item>
        </style>
    
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <LinearLayout
            android:layout_width="315dp"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@drawable/shape_r6_white"
            android:orientation="vertical">
    
            <ImageView
                android:id="@+id/img"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:scaleType="center"
                android:src="@mipmap/live_notice" />
    
            <TextView
                android:id="@+id/notice"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="16dp"
                android:layout_marginRight="20dp"
                android:layout_marginBottom="16dp"
                android:gravity="center"
                android:lineSpacingMultiplier="1.2"
                android:textColor="@color/black_1e1e1e"
                android:textSize="15sp" />
    
            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="@color/green_00b395" />
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="44dp"
                android:orientation="horizontal">
    
                <TextView
                    android:id="@+id/cancel"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/shape_r6lb_white"
                    android:gravity="center"
                    android:text="以后再说"
                    android:textColor="@color/green_00b395"
                    android:textSize="16sp" />
    
                <TextView
                    android:id="@+id/ensure"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/shape_r6rb_green"
                    android:gravity="center"
                    android:text="立即更新"
                    android:textColor="@color/white"
                    android:textSize="16sp" />
            </LinearLayout>
        </LinearLayout>
    </RelativeLayout>
    
    image.png

    视图的xml中很多属性没写明,反正知道自定义对话框用来进行更新提醒就是,视图什么的自己写个自己喜欢的吧

    相关文章

      网友评论

          本文标题:app升级安装

          本文链接:https://www.haomeiwen.com/subject/esgjmctx.html