APP自动更新,直接用
public class UpdateAPP {
private static int progress; // 定义进度值
private static String savePath; // APK下载之后保存的地址
private static String saveFileName; // APK的文件名
private static RemoteViews view = null; // 用来设置通知的View
private static NotificationManager nm = null;
private static Notification nn = null; // 引入通知
private static FlikerProgressBar flikerProgressBar;
private static int a;
private static Dialog DownLoad;
private static int handmsg = 1;
private static final int DOWN_UPDATE = 0;// 下载中消息
private static final int DOWN_OVER = 1;// 下载完成消息
private static String apkDownloadPath; // 应用下载的地址
private static Context mContext;
public static void showUpdateApp(final Context context, final String message, final String url) {
mContext =context;
nm = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);//获取系统通知的服务
nn = new Notification();//创建一个通知对象
apkDownloadPath =url;
savePath = Environment.getExternalStorageDirectory()
+ "/csnw/"; //自定义下载文件保存地址
saveFileName = savePath + "csnw.apk"; //自定义文件名
//可根据需求加入自己设计的dialog
AlertDialog dialog = new AlertDialog.Builder(context)
.setTitle("版本更新")
.setMessage(message)
.setCancelable(false)
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
}).setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
File apkfile = new File(saveFileName);
if(apkfile.exists()){
apkfile.delete();
}
a = 0;
view = new RemoteViews(context.getPackageName(), R.layout.download_progress_state_view);
nn.icon = R.mipmap.ic_launcher;
showDownLoad(context);
new Thread(mdownApkRunnable).start();
}
}).create();
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
public static void showDownLoad(Context context) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
DownLoad = new Dialog(context,R.style.dialog);
View layout = inflater.inflate(R.layout.dialog_download, null);
DownLoad.requestWindowFeature(Window.FEATURE_NO_TITLE);
DownLoad.addContentView(layout, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
flikerProgressBar = (FlikerProgressBar) layout.findViewById(R.id.flikerbar);
flikerProgressBar.setProgress(handmsg);
LinearLayout ll_btn_cancel =layout.findViewById(R.id.ll_btn_cancel);
ll_btn_cancel.setVisibility(View.GONE);
Button btn_cancel = (Button) layout.findViewById(R.id.btn_cancel);
btn_cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
a = 1;
DownLoad.dismiss();
}
});
DownLoad.show();
if(flikerProgressBar.getProgressText().equals("下载完成")){
a = 1;
DownLoad.dismiss();
}
}
// 下载APK的线程匿名类START
public static Runnable mdownApkRunnable = new Runnable() {
@Override
public void run() {
try {
URL url = new URL(apkDownloadPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
File file = new File(savePath);
if (!file.exists()) {
file.mkdir();
}
String apkFile = saveFileName;
File ApkFile = new File(apkFile);
FileOutputStream fos = new FileOutputStream(ApkFile);
int count = 0;
byte buf[] = new byte[1024];
do {
int numread = is.read(buf);
count += numread;
progress = (int) (((float) count / length) * 100);
if(handmsg < progress){
handmsg ++;
mHandler.sendEmptyMessage(DOWN_UPDATE);
}
if(a == 1){
fos.close();
is.close();
break;
}
// 更新进度
if (numread <= 0) {
// 下载完成通知安装
mHandler.sendEmptyMessage(DOWN_OVER);
break;
}
fos.write(buf, 0, numread);
} while (true || a == 1);// 点击取消就停止下载.
fos.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
// 下载APK的线程匿名类END
// 处理下载进度的Handler Start
public static Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case DOWN_UPDATE:
flikerProgressBar.setProgress(handmsg);
view.setProgressBar(R.id.download_progressbar, 100, handmsg,false);
view.setTextViewText(R.id.download_progress_text, handmsg + "%");
nn.contentView = view;
nn.flags = Notification.FLAG_AUTO_CANCEL;
nm.notify(0, nn);
super.handleMessage(msg);
break;
case DOWN_OVER:
nm.cancel(0);
flikerProgressBar.finishLoad();
DownLoad.dismiss();
App.showToast("下载完成");
installApk();
break;
default:
break;
}
};
};
// 安装apk
public static void installApk() {
File apkfile = new File(saveFileName);
if (!apkfile.exists()) {
App.showToast( "安装文件不存在,请检查");
return;
}
//项目的包名 自己改
if(Build.VERSION.SDK_INT>=24){
Uri apkUri = FileProvider.getUriForFile(mContext, "项目的包名"+".fileprovider", apkfile);//在AndroidManifest中的android:authorities值
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
mContext.startActivity(install);
}else{
Intent i = new Intent(Intent.ACTION_VIEW);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
i.setAction(android.content.Intent.ACTION_VIEW);
i.setDataAndType(Uri.fromFile(apkfile),
"application/vnd.android.package-archive");
mContext.startActivity(i);
}
}
/**
* 浏览器下载apk
* @param apkDownloadPath
*/
public static void downloadByBrowser(String apkDownloadPath){
Uri uri = Uri.parse(apkDownloadPath);
Intent intent = new Intent(Intent.ACTION_VIEW,uri);
mContext.startActivity(intent);
}
}
download_progress_state_view
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingRight="15dp"
android:orientation="horizontal" >
<!-- 通知栏里通知的图标(也就是应用的图标) -->
<ImageView
android:id="@+id/download_progress_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_launcher"/>
<!-- 通知栏里的下载进度条 -->
<ProgressBar
android:id="@+id/download_progressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginLeft="15dp"/>
<!-- 下载进度百分比 -->
<TextView
android:id="@+id/download_progress_text"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:paddingRight="15dp"
/>
</LinearLayout>
dialog_download
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical" >
<FlikerProgressBar
app:radius="10sp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:id="@+id/flikerbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:loadingColor="#40C4FF"
app:stopColor="#FF9800"
app:textSizeProgressBar="12sp" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1.0px"
android:layout_marginLeft="1.0px"
android:layout_marginRight="1.0px"
android:layout_marginTop="0sp"
android:background="#bbbbbb" />
<LinearLayout
android:id="@+id/ll_btn_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0sp"
android:background="#dddddd"
android:gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5sp"
android:layout_marginLeft="10sp"
android:layout_marginRight="10sp"
android:layout_marginTop="5sp"
android:layout_weight="1"
android:background="@drawable/bg_green_8dp_bottom"
android:text="取消"
android:textColor="#ffffff"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
R.style.dialog
<style name="dialog" parent="@android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<item name="android:backgroundDimEnabled">false</item>
<item name="android:background">#00000000</item>
</style>
FlikerProgressBar
public class FlikerProgressBar extends View implements Runnable {
private PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
private int DEFAULT_HEIGHT_DP = 35;
private int borderWidth;
private float maxProgress = 100f;
private Paint textPaint;
private Paint bgPaint;
private Paint pgPaint;
private String progressText;
private Rect textRect;
private RectF bgRectf;
/**
* 左右来回移动的滑块
*/
private Bitmap flikerBitmap;
/**
* 滑块移动最左边位置,作用是控制移动
*/
private float flickerLeft;
/**
* 进度条 bitmap ,包含滑块
*/
private Bitmap pgBitmap;
private Canvas pgCanvas;
/**
* 当前进度
*/
private float progress;
private boolean isFinish;
private boolean isStop;
/**
* 下载中颜色
*/
private int loadingColor;
/**
* 暂停时颜色
*/
private int stopColor;
/**
* 进度文本、边框、进度条颜色
*/
private int progressColor;
private int textSize;
private int radius;
private Thread thread;
BitmapShader bitmapShader;
public FlikerProgressBar(Context context) {
this(context, null, 0);
}
public FlikerProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlikerProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(attrs);
}
private void initAttrs(AttributeSet attrs) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.FlikerProgressBar);
try {
textSize = (int) ta.getDimension(R.styleable.FlikerProgressBar_textSizeProgressBar, 12);
loadingColor = ta.getColor(R.styleable.FlikerProgressBar_loadingColor, Color.parseColor("#40c4ff"));
stopColor = ta.getColor(R.styleable.FlikerProgressBar_stopColor, Color.parseColor("#ff9800"));
radius = (int) ta.getDimension(R.styleable.FlikerProgressBar_radius, 0);
borderWidth = (int) ta.getDimension(R.styleable.FlikerProgressBar_borderWidth, 1);
} finally {
ta.recycle();
}
}
private void init() {
bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
bgPaint.setStyle(Paint.Style.STROKE);
bgPaint.setStrokeWidth(borderWidth);
pgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
pgPaint.setStyle(Paint.Style.FILL);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(textSize);
textRect = new Rect();
bgRectf = new RectF(borderWidth, borderWidth, getMeasuredWidth() - borderWidth, getMeasuredHeight() - borderWidth);
if (isStop) {
progressColor = stopColor;
} else {
progressColor = loadingColor;
}
flikerBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.flicker);
flickerLeft = -flikerBitmap.getWidth();
initPgBimap();
}
private void initPgBimap() {
pgBitmap = Bitmap.createBitmap(getMeasuredWidth() - borderWidth, getMeasuredHeight() - borderWidth, Bitmap.Config.ARGB_8888);
pgCanvas = new Canvas(pgBitmap);
thread = new Thread(this);
thread.start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int height = 0;
switch (heightSpecMode) {
case MeasureSpec.AT_MOST:
height = dp2px(DEFAULT_HEIGHT_DP);
break;
case MeasureSpec.EXACTLY:
case MeasureSpec.UNSPECIFIED:
height = heightSpecSize;
break;
}
setMeasuredDimension(widthSpecSize, height);
if (pgBitmap == null) {
init();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//背景
drawBackGround(canvas);
//进度
drawProgress(canvas);
//进度text
drawProgressText(canvas);
//变色处理
drawColorProgressText(canvas);
}
/**
* 边框
*
* @param canvas
*/
private void drawBackGround(Canvas canvas) {
bgPaint.setColor(progressColor);
//left、top、right、bottom不要贴着控件边,否则border只有一半绘制在控件内,导致圆角处线条显粗
canvas.drawRoundRect(bgRectf, radius, radius, bgPaint);
}
/**
* 进度
*/
private void drawProgress(Canvas canvas) {
pgPaint.setColor(progressColor);
float right = (progress / maxProgress) * getMeasuredWidth();
pgCanvas.save();
pgCanvas.clipRect(0, 0, right, getMeasuredHeight());
pgCanvas.drawColor(progressColor);
pgCanvas.restore();
if (!isStop) {
pgPaint.setXfermode(xfermode);
pgCanvas.drawBitmap(flikerBitmap, flickerLeft, 0, pgPaint);
pgPaint.setXfermode(null);
}
//控制显示区域
bitmapShader = new BitmapShader(pgBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
pgPaint.setShader(bitmapShader);
canvas.drawRoundRect(bgRectf, radius, radius, pgPaint);
}
/**
* 进度提示文本
*
* @param canvas
*/
private void drawProgressText(Canvas canvas) {
textPaint.setColor(progressColor);
progressText = getProgressText();
textPaint.getTextBounds(progressText, 0, progressText.length(), textRect);
int tWidth = textRect.width();
int tHeight = textRect.height();
float xCoordinate = (getMeasuredWidth() - tWidth) / 2;
float yCoordinate = (getMeasuredHeight() + tHeight) / 2;
canvas.drawText(progressText, xCoordinate, yCoordinate, textPaint);
}
/**
* 变色处理
*
* @param canvas
*/
private void drawColorProgressText(Canvas canvas) {
textPaint.setColor(Color.WHITE);
int tWidth = textRect.width();
int tHeight = textRect.height();
float xCoordinate = (getMeasuredWidth() - tWidth) / 2;
float yCoordinate = (getMeasuredHeight() + tHeight) / 2;
float progressWidth = (progress / maxProgress) * getMeasuredWidth();
if (progressWidth > xCoordinate) {
canvas.save();
float right = Math.min(progressWidth, xCoordinate + tWidth * 1.1f);
canvas.clipRect(xCoordinate, 0, right, getMeasuredHeight());
canvas.drawText(progressText, xCoordinate, yCoordinate, textPaint);
canvas.restore();
}
}
public void setProgress(float progress) {
if (!isStop) {
if (progress < maxProgress) {
this.progress = progress;
} else {
this.progress = maxProgress;
finishLoad();
}
invalidate();
}
}
public void setStop(boolean stop) {
isStop = stop;
if (isStop) {
progressColor = stopColor;
thread.interrupt();
} else {
progressColor = loadingColor;
thread = new Thread(this);
thread.start();
}
invalidate();
}
public void finishLoad() {
isFinish = true;
setStop(true);
}
public void toggle() {
if (!isFinish) {
if (isStop) {
setStop(false);
} else {
setStop(true);
}
}
}
@Override
public void run() {
int width = flikerBitmap.getWidth();
try {
while (!isStop && !thread.isInterrupted()) {
flickerLeft += dp2px(5);
float progressWidth = (progress / maxProgress) * getMeasuredWidth();
if (flickerLeft >= progressWidth) {
flickerLeft = -width;
}
postInvalidate();
Thread.sleep(20);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 重置
*/
public void reset() {
setStop(true);
progress = 0;
isFinish = false;
isStop = false;
progressColor = loadingColor;
progressText = "";
flickerLeft = -flikerBitmap.getWidth();
initPgBimap();
}
public float getProgress() {
return progress;
}
public boolean isStop() {
return isStop;
}
public boolean isFinish() {
return isFinish;
}
public String getProgressText() {
String text = "";
if (!isFinish) {
if (!isStop) {
text = "下载中" + progress + "%";
} else {
text = "继续";
}
} else {
text = "下载完成";
}
return text;
}
private int dp2px(int dp) {
float density = getContext().getResources().getDisplayMetrics().density;
return (int) (dp * density);
}
}

FlikerProgressBar.png

flicker.png