JNI 之 windows下增量更新全过程

一、先看看效果图


二、简述实现过程

因为我这里是自己在编译,不是服务器给编译生成差分包,所以我这里是在本地生成差分包,然后在把差分包传到服务器然后下载即可

三、编译环境

win7系统  Android  studio 2.3    jdk1.8  Eclipse(生成差分包) 、vs2013(编译bsdiff源码生成dll)

四、实现步骤

1、创建Android项目,并创建native方法

public class BsPatch {
	//oldfile newfile patchfile
	static{
		System.loadLibrary("bspatch");
	}
	
	
	/**
	 * 合并
	 * @param oldfile
	 * @param newfile
	 * @param patchfile
	 */
	public  native  static void patch(String oldfile,String newfile,String patchfile);
}
2、因为合并是依赖开源项目bzip2的,所以导入他的c文件和头文件

3、引入bspatch.c的文件并修改头文件,和main方法

#include <jni.h>
#include "com_xiaofan_testdiff_utils_BsPatch.h"
#include "bzip2/bzlib.c"
#include "bzip2/crctable.c"
#include "bzip2/compress.c"
#include "bzip2/decompress.c"
#include "bzip2/randtable.c"
#include "bzip2/blocksort.c"
#include "bzip2/huffman.c"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <unistd.h>
#include <fcntl.h>

int bspatch_main(int argc,char * argv[])
4、实现native方法

JNIEXPORT void JNICALL Java_com_xiaofan_testdiff_utils_BsPatch_patch
        (JNIEnv * env, jclass jcls, jstring oldfile_jstr,
         jstring newfile_jstr, jstring patchfile_jstr){

    int argc = 4;
    //参数
    char* oldfile = (char*)(*env)->GetStringUTFChars(env,oldfile_jstr, JNI_FALSE);
    char* newfile = (char*)(*env)->GetStringUTFChars(env,newfile_jstr, JNI_FALSE);
    char* patchfile = (char*)(*env)->GetStringUTFChars(env,patchfile_jstr, JNI_FALSE);


    char* argv[4];
    argv[0] = "bspatch";
    argv[1] = oldfile;
    argv[2] = newfile;
    argv[3] = patchfile;


    bspatch_main(argc, argv);

    (*env)->ReleaseStringUTFChars(env,oldfile_jstr, argv[1]);
    (*env)->ReleaseStringUTFChars(env,newfile_jstr, argv[2]);
    (*env)->ReleaseStringUTFChars(env,patchfile_jstr, argv[3]);
}

5、在Eclipse下创建java项目,创建native方法

6、然后使用javah命令生成头文件,然后把头文件引入到vs2013中

7、在vs中创建项目,导入bsdiff的源码,因为我们是要生成差分包,所以去掉了bspatch.cpp


8、修改bsdiff.cpp的方法

1、修改头部,解决非安全和函数过时问题

//解决非安全的函数
#define _CRT_SECURE_NO_WARNINGS
//解决过时函数
#define _CRT_NONSTDC_NO_DEPRECATE
#include "com_xiaofan_BsDiff.h"
#include <stdlib.h>
#include "bzlib.h"
#include <stdio.h>
#include <string.h>
//#include <err.h>
//#include <unistd.h>
#include <io.h>
#include <fcntl.h>
//#include <sys/wait.h>
2、修改cpp的入口文件,因为我们是当做dll调用

//int main(int argc,char *argv[])
int bsdiff_main(int argc, char *argv[])

9、实现natvie方法

JNIEXPORT void JNICALL Java_com_xiaofan_BsDiff_diff
(JNIEnv * env, jclass jcls, jstring oldfile_jstr, jstring newfile_jstr, jstring patchfile_jstr){
	
	int argc = 4;
	//参数
	char* oldfile = (char*)env->GetStringUTFChars(oldfile_jstr, JNI_FALSE);
	char* newfile = (char*)env->GetStringUTFChars(newfile_jstr, JNI_FALSE);
	char* patchfile = (char*)env->GetStringUTFChars(patchfile_jstr, JNI_FALSE);


	char* argv[4];
	argv[0] = "bsdiff";
	argv[1] = oldfile;
	argv[2] = newfile;
	argv[3] = patchfile;


	bsdiff_main(argc, argv);

	env->ReleaseStringUTFChars(oldfile_jstr, oldfile);
	env->ReleaseStringUTFChars(newfile_jstr, newfile);
	env->ReleaseStringUTFChars(patchfile_jstr, patchfile);
	
}
10、然后在main方法中调用

public class BsDiffTest {
	static String oldfile="D:/TestDiff_old.apk";
	static String newfile="D:/TestDiff_new.apk";
	static String patchfile="D:/diff.patch";
	public static void main(String[] args) {
		//得到差分包
		BsDiff.diff(oldfile, newfile, patchfile);
			
	}

}
注意:
为什么是三个参数,因为在bsdiff.cpp的(if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);)这句话中得到的

11、在Activity中实现文件patch的下载并且调用native方法,实现文件的合并,并且生成新的包,然后去安装

我这里是直接搁在我的linux服务器的apache的

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        findViewById(R.id.button1).setOnClickListener(new  View.OnClickListener() {

            @Override
            public void onClick(View v) {
                new ApkUpdateTask().execute();
            }
        });
    }
    class ApkUpdateTask extends AsyncTask<Void, Void, Boolean> {

        @Override
        protected Boolean doInBackground(Void... params) {
            try {
                Log.i("wxf", "开始下载");
                // 1、下载差分包
                File patchFile = DownloadUtils
                        .download(Constants.URL_PATCH_DOWNLOAD);
                // 2、合并得到最新版本的APK文件
                /**
                 * oldfile 获取当前应用的apk文件(data/app)
                 */
                String oldfile = ApkUtils.getSourceApkPath(MainActivity.this,
                        Constants.PACKAGE_NAME);
                String newfile = Constants.NEW_APK_PATH;
                String patchfile = patchFile.getAbsolutePath();

                Log.i("wxf", "oldfile:" + oldfile);
                Log.i("wxf", "newfile:" + newfile);
                Log.i("wxf", "patchfile:" + patchfile);

                BsPatch.patch(oldfile, newfile, patchfile);

            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
            return true;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            // 3、安装
            if(result){
                Toast.makeText(MainActivity.this, "您正在进行无流量更新", Toast.LENGTH_LONG).show();
                ApkUtils.installApk(MainActivity.this, Constants.NEW_APK_PATH);
            }
        }

    }

}
DownloadUtils

public class DownloadUtils {
    /**
     * 下载差分包
     *
     * @param url
     * @return
     * @throws Exception
     */
    public static File download(String url) {
        File file = null;
        InputStream is = null;
        FileOutputStream os = null;
        try {
            file = new File(Environment.getExternalStorageDirectory(), Constants.PATCH_FILE);
            if (file.exists()) {
                file.delete();
            }
            HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setDoInput(true);
            is = conn.getInputStream();
            os = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }

}
Constants

public class Constants {

    public static final String PATCH_FILE = "diff.patch";
   //服务器文件路径
    public static final String URL_PATCH_DOWNLOAD = "http://*.**.*/" + PATCH_FILE;

    public static final String PACKAGE_NAME = "com.xiaofan.testdiff";

    public static final String SD_CARD = Environment.getExternalStorageDirectory() + File.separator;

    //新版本apk的目录
    public static final String NEW_APK_PATH = SD_CARD + "test_apk_new.apk";

    public static final String PATCH_FILE_PATH = SD_CARD + PATCH_FILE;

}
ApkUtils
public class ApkUtils {
    /**
     * 获取已安装Apk文件的源Apk文件
     * 如:/data/app/my.apk
     *
     * @param context
     * @param packageName
     * @return
     */
    public static String getSourceApkPath(Context context, String packageName) {
        if (TextUtils.isEmpty(packageName))
            return null;

        try {
            ApplicationInfo appInfo = context.getPackageManager()
                    .getApplicationInfo(packageName, 0);
            return appInfo.sourceDir;
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 安装Apk
     *
     * @param context
     * @param apkPath
     */
    public static void installApk(Context context, String apkPath) {

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.parse("file://" + apkPath),
                "application/vnd.android.package-archive");

        context.startActivity(intent);
    }
}


我会在我的下载里边放入我用的所有编译文件



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值