增量更新

 

            最近在学习kotlin这是写的第一篇kotlin相关的博客。平时我们做更新都是下载版本的apk,然后在安装。这样子很浪费用户的流量。今天来讲一种增量更新的方法。就是新旧版本的apk对比,讲两版的不一样的地方生成一个差分包。然后每次下载差分包,和旧版本的apk合并成新的apk,这样子可以帮用户节约好多流量。

一,得到差分包。

          要生成差分包,我们需要借助一个工具bsdiff.exe,想详细了解这个工具的可以自己取百度,我们这里只告诉大家怎么使用。先下载工具bsdiff4.3-win32.rar,然后解压。解压之后里面有测试的新旧版本的apk(1.0.apk和2.0.apk) 和生成的差分包(demo.patch)。你可以先备份一份,然后删掉换上自己的apk,也可以直接用这个测试。

           解压bsdiff4.3-win32.rar之后,在文件夹里打开cmd命令框。输入命名    bsdiff oldfile newfile patchfile,然后会生成新的差分包。

二,添加相关的引用。

     kotlin开发为了开发方便,我们可以先集成anko到自己的项目(https://github.com/Kotlin/anko)。在Module的build.gradle添加依赖implementation "org.jetbrains.anko:anko:0.10.8"。就可以了。

   和并差分包还需要添加一个依赖,他在github上的地址https://github.com/jiyouliang2/SmartUpdateDemo。添加的方法很简单。

    1. 在project的build.gradle添加如下代码(如下图)

allprojects {
    repositories {
        maven { url "https://jitpack.io" }
    }
}

 

   2. 在Module的build.gradle添加依赖(如下图)

compile 'com.github.jiyouliang2:SmartUpdateDemo:1.0.1'

三,直接上代码。

只要的工作都在MainActivity里面。注释写的很详细,不在啰嗦。

class MainActivity : AppCompatActivity() {
    //6.0以上的需要动态获取权限
    private val REQUEST_EXTERNAL_STORAGE = 1
    private var PERMISSIONS_STORAGE = arrayOf("android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE")

    private val mDialog: ProgressDialog by lazy { ProgressDialog(this) }//懒加载


    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        verifyStoragePermissions()//6.0以上要动态加载权限
        //动态升级
        updata.onClick {
            //8.0以上的版本要先判断是否有安装应用的权限。
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {  //兼容8.0
                if (!packageManager.canRequestPackageInstalls()) {
                    startInstallPermissionSettingActivity()
                    return@onClick
                }
            }

            //https://github.com/jiyouliang2/SmartUpdateDemo   github上合并差分包和旧版本的项目地址。
            var pm: PackageManager = packageManager//获得包管理器
            var appInfo = pm.getApplicationInfo(packageName, 0)//通过包管理器得到app信息
            var oldPath = appInfo.sourceDir;//旧版本路径
            val newApkFile = File(getExternalStorageDirectory(), "2.0.apk")//新版本保存路径(将要生成的新版本的apk存放的路径)
            val patchFile = File(Environment.getExternalStorageDirectory(), "demo.patch")//更新包路径 手动的讲demo.patch放到该路径,或者网上下载到该路径
            if (patchFile.exists()) {
                doAsync {
                    val result = PatchUtil.patch(oldPath, newApkFile.absolutePath, patchFile.absolutePath)//合并patch和旧的apk,生成新的apk
                    if (result == 0) {
                        //合并成功,安装apk
                        runOnUiThread {
                            mDialog.dismiss()
                            install(newApkFile)//安装apk
                        }
                    } else {
                        toast("合并失败")
                    }
                }

            } else {
                toast("请将差分包demo.patch保存到sdcard")
            }
        }
    }

    private fun install(apkFile: File) {
        try {
            intent = Intent(Intent.ACTION_VIEW)

            //兼容7.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
                var contentUri = FileProvider.getUriForFile(this, "$packageName.fileProvider", apkFile)
                intent.setDataAndType(contentUri, "application/vnd.android.package-archive")
            } else {
                intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            }
            startActivity(intent)
        } catch (e: Throwable) {
            e.printStackTrace()

        }
    }

    /**
     * 8.0以上的版本需要判断是否有权限安装应用
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    fun startInstallPermissionSettingActivity() {
        var packageURI = Uri.parse("package:" + getPackageName())
        //注意这个是8.0新API
        var intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI)
        startActivityForResult(intent, 10086)
    }



    /**
     * android 动态权限申请
     */
    private fun verifyStoragePermissions() {
        try {
            //检测是否有写的权限
            var permission = ActivityCompat.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE")

            if (permission != PackageManager.PERMISSION_GRANTED) {
                // 没有写的权限,去申请写的权限,会弹出对话框
                ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

}

 这个是布局文件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:text="v2.0"
        android:textSize="20sp"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/updata"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="更新"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</LinearLayout>

6.0以上的安卓版本,访问sd卡是要动态添加权限的。8.0以上的安装apk也要做处理,这些代码中都处理了,不知道的小伙伴可以自己百度下。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.administrator.demokt1">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
    
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.administrator.demokt1.fileProvider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>
    </application>

</manifest>

如果还有疑问或者还不成功的小伙伴可以取下载源码。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章