Android开发笔记--检查更新app功能

这篇博客详细介绍了如何在Android应用中实现检查更新的功能,包括从用户触发更新检查,到对比版本信息,下载新版本,直至最终更新的完整流程。作者强调了检查更新的核心逻辑,如获取服务器的JSON数据,解析并比较版本号,以及如何处理下载和更新操作。此外,还提供了MyApplication类的使用,以及在manifest.xml中设置versionCode和versionName的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android检查更新app是一个比较常见的功能。但是功能也比较单一。也是一块可以复用的代码。所以我这里想把自己检查更新的代码写下来。如果想使用直接移植过去就好。也不用重复开发了。

整个检查更新的大致过程

1.需要用户触发检查更新,所以界面里做个btn
2.用户点击btn后触发事件,弹出一个dialog或者toast提示用户是否是最新版本,需不需要更新
3.btn点击触发后,我们不能直接在UI层里做检查更新的操作。所以检查更新的逻辑就要开线程。这里的代码一想就是重点了吧。所以封装出来让btn onClick事件调用比较好。
4.检查更新的逻辑一般都是这样的:
第一,检查。
客户端内持有一个检查更新的url.这个url存在的目的就是为了检查是不是最新版本。一般这个url从服务端传来的内容包括:apk下载url、最新的apk版本、apk包名、apk更新信息。哈哈。是不是特别熟悉?传来的东西我们需要解析啦!那么,就要和后端的小伙伴商量定接口了吧?这里直接意淫一下,我们的接口定好了。服务器就用json提供上面说的四块儿内容。我们从url取出来就是json格式的数据了。拿回来以后直接json解析,解析完了就封装到本地的封装对象供我们使用。
既然是检查,那你拿回来最新版本的信息是不是跟本地有对比才有新旧之分?顺理成章。我们需要拿到本地的版本信息。上网查查有没有这么一个类啊?哎呦喂,果然有!就是PackageManager。好,通过它。我们有了本地的版本信息啦!下面就是一个核心而又简单的逻辑了。对比版本,if 后台版本>本地版本,那么下载后台版本(这里还不是更新呢)。else 告诉用户已经是最新版本。
第二,下载。
这一块想一想跟检查貌似以两块代码。嗯,我分开写,方便理思路。利用上面检查给的apk下载url下载到本地文件夹。下载的过程有时候需要给用户展示。所以这里用handler在ui展现一下下载过程。
第三,更新。
下载好了,剩下更新了。

MyApplication.java

这里写一个MyApplication类继承自Application,在里面获取一个全局的context,从此不再为拿不到context心烦了。

public class MyApplication extends Application {
    public static Context mContext;
    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }
}

manifest.xml

versionCode versionName要写出来。是用来比较版本的。这里选用versionCode比较。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zharma.updatetest"
    android:versionCode="1"
    android:versionName="1.0.0">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

布局

首先说一下最直观的,apk更新最多出现在的就是在设置之类的界面中。这些界面的布局细节就不说了。这里为了以后复用简便也不做冗余的嵌套。直接就是一个btn。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.zharma.updatetest.MainActivity">

    <Button
        android:id="@+id/btnDownload"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="检查更新"/>
</RelativeLayout>

btn点击事件

public class MainActivity extends Activity {
    private Button btnDownload;
    private View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btnDownload:
                //在这里做检查业务逻辑
                break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnDownload = (Button) findViewById(R.id.btnDownload);
        btnDownload.setOnClickListener(listener);
    }

}

好了。界面搭的简陋一点能跑就行。

检查、下载、更新

检查是一个url请求,然后返回后台提供的版本json数据,用gson解析、封装到封装对象中。获取本地版本号(我们用versionCode比较版本)对比处理。
这个过程我就一起写下来。

封装类:
UpdateInfo

public class UpdateInfo {
    public int versionCode;
    public String versionName;
    public String url;
    public String description;
}
/**
 * Created by dahe on 16/8/21.
 */
public class CheckVersion implements Runnable{
    //VERSIONINFO_URL是访问服务器拿到查询更新json数据的url,一般这个是在单独的一个数据类中写的。那样的话让CheckVersion继承自那个类。拿到url来用。现在这里设为空是为了方便看,还有以后更改url。
    private static final String VERSIONINFO_URL = "我现在是空的,这个要自己填自己的查询url";
    private static final int HAVE_NEW_VERSION = 0;
    private static final int ALREADY_NEW_VERSION = 1;
    private Context context = MyApplication.mContext;
    private UpdateInfo updateInfo;

    //获取到主线程的looper,对UI操作
    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case HAVE_NEW_VERSION:
                    openUpdateDialog();
                    break;
                case ALREADY_NEW_VERSION:
                    Toast.makeText(context, "已经是最新版本", Toast.LENGTH_LONG).show();
                    break;
            }
        }
    };

    private void openUpdateDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("版本有更新");
        builder.setMessage(updateInfo.description);
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                downloadNewVersion();
            }
        });
        builder.setNegativeButton("取消", null);
    }

    private void downloadNewVersion() {
        final ProgressDialog pd = new ProgressDialog(context);
        pd.setTitle("更新进度");
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.show();

        new Thread(new Runnable() {
            InputStream is;
            BufferedInputStream bis;
            FileOutputStream fos;

            @Override
            public void run() {
                //这里完成下载
                try {
                    URL downloadUrl = new URL(updateInfo.url);
                    HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);

                    int maxlength = connection.getContentLength();
                    pd.setMax(maxlength);

                    is = connection.getInputStream();
                    bis = new BufferedInputStream(is);

                    File file = new File(Environment.getExternalStorageDirectory(), "newversion.apk");
                    fos = new FileOutputStream(file);

                    byte[] buffer = new byte[1024];
                    int len;
                    int loaded = 0;

                    while ((len = bis.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                        loaded += len;
                        pd.setProgress(loaded);
                    }

                    installApk(file);
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        is.close();
                        bis.close();
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();

    }

    private void installApk(File file) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        context.startActivity(intent);
    }

    @Override
    public void run() {
        try {
            String s = VERSIONINFO_URL;
            URL url = new URL(s);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);

            InputStream is = connection.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);

            Gson gson = new Gson();
            updateInfo = gson.fromJson(br, UpdateInfo.class);
            //后台版本
            int serverVersionCode = updateInfo.versionCode;

            //本地版本获取
            int localVersionCode = getLocalVersionCode();

            if (serverVersionCode > localVersionCode) {
                //后台版本新!所以弹框提醒用户有新版本,让用户操作dialog更新
                Message msg = new Message();
                msg.what = HAVE_NEW_VERSION;
                mHandler.sendMessage(msg);

            } else {
                //后台没有新版本,所以在界面反馈用户不用更新
                Message msg = new Message();
                msg.what = ALREADY_NEW_VERSION;
                mHandler.sendMessage(msg);
            }


        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private int getLocalVersionCode() throws PackageManager.NameNotFoundException {
        PackageManager pm = context.getPackageManager();
        PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);
        int versionCode = info.versionCode;
        return versionCode;
    }
}

好了,主要逻辑写完了那么就可以在btn中开线程做查询、下载、更新的事情了。

public class MainActivity extends Activity {
    private Button btnDownload;
    private View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btnDownload:
                //在这里做检查业务逻辑
                CheckVersion checkVersion = new CheckVersion();
                new Thread(checkVersion).start();
                break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnDownload = (Button) findViewById(R.id.btnDownload);
        btnDownload.setOnClickListener(listener);
    }

}

到这里,代码片全部写完。
最后用一张图回顾一下我都做了什么:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值