在Android7.0的手机上,自动更新的时候出现包解析异常,在其他的手机上没有这个问题。
原因:
Android7.0引入私有目录被限制访问和StrictMode API 。私有目录被限制访问是指在Android7.0中为了提高应用的安全性,在7.0上应用私有目录将被限制访问。StrictMode API是指禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,则会报出异常。
解决办法:
第一步:在AndroidManifest.xml中注册provider,provider可以向应用外提供数据。
1
2
3
4
5
6
7
8
9
|
<provider
android:authorities= "包名.fileprovider"
android:name= "android.support.v4.content.FileProvider"
android:grantUriPermissions= "true" //这是设置uri的权限
android:exported= "false" >
<meta-data
android:name= "android.support.FILE_PROVIDER_PATHS"
android:resource= "@xml/file_paths" /> //在第二步的时候会有介绍
</provider>
|
第二步:在res/xml中创建file_paths.xml文件。
1
2
3
4
5
6
|
<? xml version = "1.0" encoding = "utf-8" ?>
< resources >
< paths >
< external-path path = "" name = "download" />
</ paths >
</ resources >
|
第三步:贴出我的自动更新下载的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
public class UpdateManager {
private Context mContext;
private static String savePath ;
private String saveFileName ;
private ProgressBar mProgress; //下载进度条控件
private static final int DOWNLOADING = 1 ; //表示正在下载
private static final int DOWNLOADED = 2 ; //下载完毕
private static final int DOWNLOAD_FAILED = 3 ; //下载失败
private int progress; //下载进度
private boolean cancelFlag = false ; //取消下载标志位
private String serverVersion; //从服务器获取的版本号
private String apkUrl;
// private String apkUrl = "http://liuliu.lejuhuyu.com/AndroidApk/liuliu-dashou-app-1.0.2.apk";
private String clientVersion; //客户端当前的版本号
private String updateDescription = "请更新当前最新版本" ; //更新内容描述信息
private String forceUpdate; //是否强制更新
private String update;
private VersionBean mVersionBean;
private AlertDialog alertDialog1, alertDialog2; //表示提示对话框、进度条对话框
public UpdateManager(Context context,VersionBean versionBean) {
this .mContext = context;
this .mVersionBean = versionBean;
apkUrl = "http://liuliu.lejuhuyu.com/AndroidApk/liuliu-dashou-app-" +versionBean.getLastVersion()+ ".apk" ;
savePath = Environment.DIRECTORY_DOWNLOADS;
saveFileName = savePath + "/liuliu-dashou-app-" +versionBean.getLastVersion()+ ".apk" ;
}
/** 显示更新对话框 */
public void showNoticeDialog() {
serverVersion = mVersionBean.getLastVersion();
clientVersion = mVersionBean.getVersion();
L.e( "apkUrl=" +apkUrl);
L.e( "savePath=" +savePath);
L.e( "saveFileName=" +saveFileName);
// forceUpdate = StringUtils.getVersion();
// forceUpdate = "1";
forceUpdate = mVersionBean.getImportant();
update = mVersionBean.getUpdate();
//如果版本最新,则不需要更新
if (serverVersion.equals(clientVersion))
return ;
if (update.equals( "2" ))
return ;
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle( "发现新版本 :" + serverVersion);
dialog.setMessage(updateDescription);
dialog.setPositiveButton( "现在更新" , new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
arg0.dismiss();
showDownloadDialog();
}
});
//是否强制更新
if (forceUpdate.equals( "2" )) {
dialog.setNegativeButton( "待会更新" , new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
arg0.dismiss();
}
});
}
alertDialog1 = dialog.create();
alertDialog1.setCancelable( false );
alertDialog1.show();
}
/** 显示进度条对话框 */
public void showDownloadDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle( "正在更新" );
final LayoutInflater inflater = LayoutInflater.from(mContext);
View v = inflater.inflate(R.layout.softupdate_progress, null );
mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
dialog.setView(v);
//如果是强制更新,则不显示取消按钮
// if (forceUpdate.equals("1")) {
// dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
// @Override
// public void onClick(DialogInterface arg0, int arg1) {
// // TODO Auto-generated method stub
// arg0.dismiss();
// cancelFlag = false;
// }
// });
// }
alertDialog2 = dialog.create();
alertDialog2.setCancelable( false );
alertDialog2.show();
//下载apk
downloadAPK();
}
DownloadManager manager;
Cursor cursor;
DownloadManager.Request down;
DownloadManager.Query query;
ContentObserver contentObserver;
/** 下载apk的线程 */
public void downloadAPK() {
manager = (DownloadManager) LiuLiuApplication.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
down = new DownloadManager.Request(Uri.parse(apkUrl));
// 设置允许使用的网络类型,这里是移动网络和wifi都可以
down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
| DownloadManager.Request.NETWORK_WIFI);
// 显示下载界面
down.setVisibleInDownloadsUi( true );
// 设置下载路径和文件名
down.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "liuliu-dashou-app-" +mVersionBean.getLastVersion() + ".apk" );
down.setMimeType( "application/vnd.android.package-archive" );
// 设置为可被媒体扫描器找到
down.allowScanningByMediaScanner();
down.setAllowedOverRoaming( false );
// down.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
long id = manager.enqueue(down);
query = new DownloadManager.Query().setFilterById(id);
contentObserver = new ContentObserver(mHandler) {
@Override
public void onChange( boolean selfChange) {
// super.onChange(selfChange);
boolean downloading = true ;
while (downloading){
cursor = manager.query(query);
try {
if (cursor != null && cursor.moveToFirst()) {
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
progress = ( int ) ((bytes_downloaded * 100 ) / bytes_total);
mHandler.sendEmptyMessage(DOWNLOADING);
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))==DownloadManager.STATUS_SUCCESSFUL) {
mHandler.sendEmptyMessage(DOWNLOADED);
} else if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))==DownloadManager.STATUS_FAILED){
mHandler.sendEmptyMessage(DOWNLOAD_FAILED);
}
}
} catch (Exception e){
e.printStackTrace();
mHandler.sendEmptyMessage(DOWNLOAD_FAILED);
} finally {
if (cursor != null ){
downloading = false ;
cursor.close();
}
}
}
}
};
mContext.getContentResolver().registerContentObserver(Uri.parse( "content://downloads/" ), true ,contentObserver);
}
/** 更新UI的handler */
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case DOWNLOADING:
mProgress.setProgress(progress);
break ;
case DOWNLOADED:
if (alertDialog2 != null )
alertDialog2.dismiss();
installAPK();
break ;
case DOWNLOAD_FAILED:
ToastUtil.getInstance(mContext, "网络断开,请稍候再试" , false ).show();
break ;
default :
break ;
}
}
};
/** 下载完成后自动安装apk */
public void installAPK() {
File apkFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "liuliu-dashou-app-" +mVersionBean.getLastVersion() + ".apk" );
if (!apkFile.exists()) {
return ;
}
if (Build.VERSION.SDK_INT>= 24 ){
Uri apkUri = FileProvider.getUriForFile(mContext, LiuLiuApplication.getContext().getPackageName()+ ".fileprovider" , apkFile);
Intent install = new Intent(Intent.ACTION_VIEW);
install.addCategory(Intent.CATEGORY_DEFAULT);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive" );
mContext.startActivity(install);
} else {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType( "application/vnd.android.package-archive" );
intent.setData(Uri.fromFile(apkFile));
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive" );
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
}
}
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/hexiuming12/article/details/77839435