最近写的项目中有用到版本升级,所以简单的写了一个例子来实现这个功能,由于时间紧迫,代码有很多需要优化的地方,请各位大神指正。
页面大概是这个样子的:
在服务中使用okgo下载APK,下载过程中在通知栏显示下载进度,下载完成后,通知栏消失,进入APK安装页面;
主要代码:
public class Update_app {
private Context context;
private String update_url = "http://b2b.yoyoce.com/mobile/member/down";
private String apk_url = "";
private int version = 0;
private String ed_num, content, size;
public Update_app(Context context) {
this.context = context;
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
if (isNeedUpdate()) {
SharedPreferences sp = context.getSharedPreferences("update", Context.MODE_PRIVATE);
sp.getInt("num", 0);
if (sp.getInt("num", 0) != version) {
ShowDialog();
}
}
break;
}
}
};
public void update() {
get_service();
}
private boolean isNeedUpdate() {
if (getVersion() < version) {
return true;
} else {
return false;
}
}
//获取当前版本号
private int getVersion() {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
void get_service() {
OkGo.post(update_url)
.tag(this)
.connTimeOut(100000)
.readTimeOut(100000)
.writeTimeOut(100000)
.cacheKey(update_url)
.cacheTime(1000 * 60 * 60 * 24)
.cacheMode(CacheMode.FIRST_CACHE_THEN_REQUEST)
//这里给出的泛型为 ServerModel,同时传递一个泛型的 class对象,即可自动将数据结果转成对象返回
.execute(new StringCallback() {
@Override
public void onSuccess(String s, Call call, Response response) {
try {
JSONObject jsonObject = new JSONObject(s);
if (jsonObject.getInt("status") == 1) {
JSONObject jsonObject1 = jsonObject.getJSONObject("result");
apk_url = jsonObject1.getString("apk_url");
String edition = jsonObject1.getString("edition");
//展示给用户
ed_num = jsonObject1.getString("ed_num");
content = jsonObject1.getString("content");
size = jsonObject1.getString("size");
version = Integer.parseInt(edition);
handler.sendEmptyMessage(1);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
void ShowDialog() {
//弹出对话框
final LayoutInflater inflaterDl = LayoutInflater.from(context);
LinearLayout layout = (LinearLayout) inflaterDl.inflate(R.layout.update, null);
//初始化按钮
TextView update_tv_yes = (TextView) layout.findViewById(R.id.update_tv_yes);
TextView update_tv_no = (TextView) layout.findViewById(R.id.update_tv_no);
final CheckBox cb = (CheckBox) layout.findViewById(R.id.cb);
TextView new_banben = (TextView) layout.findViewById(R.id.new_banben);
TextView apk_size = (TextView) layout.findViewById(R.id.apk_size);
TextView new_context1 = (TextView) layout.findViewById(R.id.new_context1);
new_banben.setText("最新版本: " + ed_num);
apk_size.setText("新版本大小: " + size);
new_context1.setText(content);
final AlertDialog dialog = new AlertDialog.Builder(context).create();
dialog.show();
dialog.getWindow().setContentView(layout);
Window dialogWindow = dialog.getWindow();
dialogWindow.setGravity(Gravity.CENTER);
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
//屏幕宽高度
WindowManager m = ((MainActivity) context).getWindowManager();
Display d = m.getDefaultDisplay();
//lp.height = (int) (d.getHeight() * 0.4);
lp.width = (int) (d.getWidth() * 0.9);
dialogWindow.setAttributes(lp);
update_tv_yes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, Update_Service.class);
intent.putExtra("apk_url",apk_url);
context.startService(intent);
Toast.makeText(context, "下载中,请稍等…", Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
});
update_tv_no.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (cb.isChecked()) {
dialog.dismiss();
SharedPreferences sharedPreferences = context.getSharedPreferences("update", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("num", version);
editor.commit();
} else {
dialog.dismiss();
}
}
});
}
}
对话框布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="25dp"
android:paddingTop="5dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:text="发现新版本"
android:textColor="#009aff"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="#009aff" />
<TextView
android:id="@+id/new_banben"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:textSize="15sp" />
<TextView
android:id="@+id/apk_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="10dp"
android:textSize="15sp" />
<TextView
android:id="@+id/new_context"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:text="更新内容:"
android:textSize="15sp" />
<TextView
android:id="@+id/new_context1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="10dp"
android:layout_marginTop="5dp"
android:textSize="15sp" />
<CheckBox
android:id="@+id/cb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:checked="false"
android:text="忽略本版"
android:textColor="#666"
android:textSize="16sp">
</CheckBox>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/update_tv_no"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:background="@drawable/next_update_tv"
android:gravity="center"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:text="下次再说"
android:textSize="15sp" />
<TextView
android:id="@+id/update_tv_yes"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:background="@drawable/now_update_tv"
android:gravity="center"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:text="立即更新"
android:textColor="#fff"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
服务中开始下载, okgo用到的依赖:
compile 'com.lzy.net:okgo:2.0.0'
compile 'com.lzy.net:okrx:0.1.0'
compile 'com.lzy.net:okserver:1.1.0'
public class Update_Service extends Service {
private NotificationManager notifyManager;
private NotificationCompat.Builder builder;
private RemoteViews mRemoteViews;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mRemoteViews = new RemoteViews(getPackageName(), R.layout.update_progress);
mRemoteViews.setImageViewResource(R.id.icon_pg, R.mipmap.icon);
mRemoteViews.setTextViewText(R.id.pg_tv, "0%");
builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.icon)
.setContentTitle("正在下载安装包")
.setContentText("请稍等…")
.setTicker("开始更新")
.setContent(mRemoteViews);
notifyManager.notify(1, builder.build());
down(intent.getStringExtra("apk_url"));
return Service.START_STICKY;
}
void down(String url2) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String sdpath = Environment.getExternalStorageDirectory().getAbsolutePath();
OkGo.get(url2)
.tag(this)
.execute(new FileCallback(sdpath, "fenglaike.apk") {
@Override
public void onBefore(BaseRequest request) {
}
@Override
public void onSuccess(File file, Call call, Response response) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
stopSelf();
notifyManager.cancelAll();
}
@Override
public void downloadProgress(long currentSize, long totalSize, float progress, long networkSpeed) {
mRemoteViews.setProgressBar(R.id.pg, 100, (int) (Math.round(progress * 10000) * 1.0f / 100), false);
mRemoteViews.setTextViewText(R.id.pg_tv, (Math.round(progress * 10000) * 1.0f / 100) + "%");
notifyManager.notify(1, builder.build());
}
@Override
public void onError(Call call, @Nullable Response response, @Nullable Exception e) {
super.onError(call, response, e);
Toast.makeText(getApplicationContext(), "下载出错,请重新下载", Toast.LENGTH_SHORT).show();
}
});
} else {
Toast.makeText(getApplicationContext(), "存储卡装载错误", Toast.LENGTH_SHORT).show();
}
}
}
通知栏布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="65dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon_pg"
android:layout_width="45dp"
android:layout_height="45dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="15dp"
android:layout_marginLeft="10dp"
android:text="更新下载中"
android:textSize="10sp" />
<ProgressBar
android:id="@+id/pg"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3.5dp"
android:progressDrawable="@drawable/pg_style"
android:layout_marginBottom="5dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="5dp"
android:background="#debd2c"
android:max="100"
android:progress="0" />
<TextView
android:id="@+id/pg_tv"
android:layout_width="wrap_content"
android:layout_height="15dp"
android:layout_marginLeft="10dp"
android:text="25%"
android:textSize="10sp" />
</LinearLayout>
</LinearLayout>
进度条背景:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 这个是背景颜色 -->
<item android:id="@android:id/background">
<shape>
<!-- 这个是设置圆角还会直角,如果设置成0dip就是直角 -->
<corners android:radius="5dip" />
<!-- 设置背景的颜色,将startColor、centerColor、endColor都设置成同一个颜色值 -->
<!--
如果你不用颜色值也可以,可以直接用图片来代替,在item中添加这个属性就可以了,其他的不需要
android:drawable="@drawable/progressbar_bg"
-->
<gradient
android:endColor="#DDE3E4"
android:startColor="#DDE3E4" />
</shape>
</item>
<!-- 这个是第二进度条的颜色,没用到,大同小异 -->
<!--<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="5dip" />
<gradient
android:angle="270"
android:centerColor="#80C07AB8"
android:centerY="0.75"
android:endColor="#a0C07AB8"
android:startColor="#80C07AB8" />
</shape>
</clip>
</item>-->
<!-- 这个是设置你进度的颜色 -->
<item android:id="@android:id/progress">
<clip>
<shape>
<!-- 这个也是设置时圆角还是直角,左边的 -->
<corners android:radius="5dip" />
<!-- 设置进度的颜色,将startColor、centerColor、endColor都设置成同一个颜色值 -->
<gradient
android:endColor="#009aff"
android:startColor="#009aff" />
</shape>
</clip>
</item>
</layer-list>
为了在关闭应用后还可以继续下载,可以再开启一个进程:
<service
android:name=".update.Update_Service"
android:process=":download" />