君不见长松卧壑困风霜,时来屹立扶明堂。这篇文章主要讲述最全的增量更新入门 包含linux端和Android相关的知识,希望能为你提供帮助。
简介 增量更新大量用于 android各大应用市场.本文想做网络上从服务器到app客户端完整讲解.app用eclipse和android studio 最新版cmark开发ndk
如下图:
文章图片
以前一直好奇怎么做的直到知道了bsdiff库.
地址附上:
bsdiff源码地址和简介
- 大家可以从简介看到bsdiff是基于bzip2源码(bsdiff和bspatch一个用于生成差异文件补丁,另一个用于差异文件和旧文件合成新文件)
文章图片
- 下载地址说明
文章图片
文章图片
在服务器上用java后台生成差异文件
- 操作系统:ubuntu
- 集成开发环境(ide):eclipse
- 源码:bzip2 ,bsdiff
懒人链接
bzip2源码下载:
bzip2官网链接
bzip2下载链接
下载后bsdiff源码文件如下:
文章图片
- 我们看到有两个 文件一个bsdiff.c 和bspatch.c 其他文件,大家先无视(makefie可以简单理解文件工程管理的,这里可用可不用).
- 我们服务器要生成差异文件,那么只需要bsdiff.c 即可.
- 我们先简单阅读下bsdiff源码(我们直接看启动方法main):
文章图片
从上图可知 传入的参数args需要等于4 不然报错.各个参数已经在上图解释
- 由于main方法很特殊(启动方法,和java的main意义一样所以我们改一个方法名) 所以在这里我们改一个名字为 bsdiff_main
文章图片
- 编写对应java的jni方法并生成头文件.(如果大家对jni不熟悉的,就按照本博客操作即可,尽量做到让大家都明白)
文章图片
2 编写jni方法
package com.fmy;
public class JAVABsdiff {public static void main(String[] args) {}
//jni方法 用于调用bsdiff
public static native void myBsdiff(String []args);
}
3 生成对应”xxx.h”文件
1. 打开命令窗口
2. 打开目录到java工程目录到src下
3. 输入javah 包名.类名 生成对应 "
xxx.h"
头文件
文章图片
此时会在你java到src目录生成xx.h文件( 请按F5刷新)
文章图片
我们顺便打开这个文件看看
文章图片
可以看到里面有一个c语言方法
JNIEXPORT void JNICALL Java_com_fmy_JAVABsdiff_myBsdiff
(JNIEnv *, jclass, jobjectArray);
我们待会创建一个c文件实现它并将它与bsdiff_main方法关联
4 创建bsdiff.h。创建一个test.c文件 导入bsdiff.h和xxx.h 并实现
- 导入bsdiff.h并声明bsdiff_main()方法作用是用于告诉 test.c有这个方式到实现 并且可以调用
- xxx.h是我们前面调用javah 生成到头文件
#include "
com_fmy_JAVABsdiff.h"
#include<
stdio.h>
#include"
bsdiff.h"
JNIEXPORT void JNICALL Java_com_fmy_JAVABsdiff_myBsdiff
(JNIEnv * env, jclass jclas,jobjectArray attas){//GetObjectArrayElement得到到是jstring类型 而我们调用bsdiff_main(
)
传入的
//是char× 数组 所以需要转化。这里需要jni知识 所以就不太多了,
你只需把下面到内容
//复制到你到项目中即可//旧文件地址
jstring a0 =
(*env)->
GetObjectArrayElement(env,attas,0);
//转化为char ×
char *j=
(char*)(*env)->
GetStringUTFChars(env,a0,NULL);
//
jstring a1 =
(*env)->
GetObjectArrayElement(env,attas,1);
char *j1=
(char*)(*env)->
GetStringUTFChars(env,a1,NULL);
jstring a2 =
(*env)->
GetObjectArrayElement(env,attas,2);
char *j2=
(char*)(*env)->
GetStringUTFChars(env,a2,NULL);
char * agrs[] =
{"
patch"
,j,j1,j2};
bsdiff_main(4,agrs);
}
5 编译生成方式1 gcc命令
- 把上面所有到文件放入到一个文件中
- bsdiff.h
- bsdiff.c
- test.c
- xxx.h
- bzip2文件下所有源码
文章图片
打开命令窗口 打开此目录输入
$ gcc *.c -fPIC -shared -o libtest.so
然后报错
文章图片
为什么报错? 因为 前面用javah生成头文件中导入了jni.h 这里大家可以回头看看。第二我们使用env这个变量 也是jni里面所有我们需要导入。
问题来了jni.h在哪?
位于java安装目录include下
文章图片
ok我们把这个文件复制到刚才编译目录下, 继续编译
文章图片
又报错发现缺少jni_md.h 文件
报错原因:因为jni.h内部引用了jni_md.h
jni_md.h在哪?
在java安装目录到include到linux下
文章图片
我们在最后编译下
文章图片
发现还是报错xxx.c中定义main重复定义了
大家这里可以看着报错到文件 去到文件直接把main方法删除了或注释
这里我就带大家注释其中到bzip2recover.c的main
文章图片
删除或则注释上面高亮部分
其他文件大家自己删除把
再次编译一次 快疯了。。。。。
编译通过了!
文章图片
此时在目录下会生成test.so
在java调用so
package com.fmy;
public class JAVABsdiff {static{
System.load("
/media/fmy/新加卷/增量/完整/test.so"
);
}public static void main(String[] args) {String oldfile =
"
/media/fmy/新加卷/增量/old.tar"
;
String newfile =
"
/media/fmy/新加卷/增量/new.tar"
;
String patch =
"
/media/fmy/新加卷/增量/patch.patch"
;
myBsdiff(new String[]{oldfile,newfile,patch});
System.out.println("
asd"
);
}
//生成静态到patch文件
public static native void myBsdiff(String []args);
}
5 编译生成方式2 eclipse
elipse 需要安装cdt插件
- 新建C project。
- 选择project type —> > Shared Libary
- toocahins 选择Linux GCC
- finish
文章图片
- 导入第一中编译方式 最后一步的所有文件到工程中
文章图片
- 修改编译参数
- 右键项目 在弹出到菜单栏中选择Propertice
- c/c+
+
Build –>
>
Setings 在右侧窗的command输入gcc -fPIC
文章图片
- build一下在debug下就可以看到对应的so类库
eclipse cdt编译参考文献2
Android eclipse实现patch
- eclipse 新建一个Android 工程
- 右键选择Android Tools—>
>
Add Native Support 点击确定
文章图片
- 此时会在目录生成 生成一个lib目录 并且自动生成一个.cpp和Android.mk文件
- 创建jni方法
public class MainActivity extends Activity {@ Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }public static native void path(String []arrays); }
- 生jni方法头文件放入jni中
文章图片
- 把去掉bzip2源码中所有的main方法的文件拷贝到jni目录下,
- 创建一个test.c文件放入jni目录
- 把 bspatch.c放入jni目录.并修改对应的main
文章图片
文章图片
修改bspatch.c导入的bzip.h路径
文章图片
我们顺带看jni 目录
文章图片
- 编写test.c实现
#include " com_fmy_JAVA_bs.h" #include< stdio.h> JNIEXPORT void JNICALL Java_com_fmy_JAVA_1bs_myBsDiff (JNIEnv * env, jclass jclas,jobjectArray attas){ jstring a0 = (*env)-> GetObjectArrayElement(env,attas,0); char *j= (*env)-> GetStringUTFChars(env,a0,NULL); jstring a1 = (*env)-> GetObjectArrayElement(env,attas,1); char *j1= (*env)-> GetStringUTFChars(env,a1,NULL); jstring a2 = (*env)-> GetObjectArrayElement(env,attas,2); char *j2= (*env)-> GetStringUTFChars(env,a2,NULL); char * agrs[] = {" patch" ,j,j1,j2}; bsdiff_main(4,agrs); }
- 修改Android.mk文件如下
LOCAL_PATH := $(call my-dir)#目的便利jni目录下所有的.c文件MY_CPP_LIST := $(wildcard $(LOCAL_PATH)/*.c)#目的便利jni/bzip2目录下所有的.c文件MY_CPP_LIST + = $(wildcard $(LOCAL_PATH)/bzip2/*.c)include $(CLEAR_VARS)LOCAL_MODULE:= bspatch LOCAL_SRC_FILES := $(MY_CPP_LIST:$(LOCAL_PATH)/%= %)#导入Android 日志 库可以在jni中使用Log.e方法等LOCAL_LDLIBS:= -lloginclude $(BUILD_SHARED_LIBRARY)
- 获取本地apk文件路径和服务器下载好的patch(差异文件)合成
(这里偷懒模拟下就下)
public class MainActivity extends Activity {static{
System.loadLibrary("
bspatch"
);
}
@
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里用zip包模拟 增量更新不止用于 apk哦亲
File oldFile =
new File(Environment.getExternalStorageDirectory(),"
old.zip"
);
File newFile =
new File(Environment.getExternalStorageDirectory(),"
new.zip"
);
File patchFile =
new File(Environment.getExternalStorageDirectory(),"
path.patch"
);
path(new String [] {oldFile.getAbsolutePath(),newFile.getAbsolutePath(),patchFile.getAbsolutePath()});
//path();
Log.e("
test"
, "
asd"
);
//Log.e("
fmy"
, "
=
=
=
=
=
=
=
=
=
=
=
=
"
+
path);
}//public static native void path();
public static native void path(String []arrays);
}
Android studio2.2实现patch
用CMake 构建ndk开发,这里不详细说了
CMake教程
用as创建一个工程的时候勾选 ‘include c+ + support’
文章图片
此时 工程目录下有个main/cpp文件夹
项目工程下会有个CMakeList.txt文件
- 导入bzip2(去掉文件中带有main方法的文件代码) 放入cpp文件夹中
- 创建一个jni方法
public class MainActivity extends AppCompatActivity {// Used to load the ' native-lib' library on application startup. static { System.loadLibrary(" native-lib" ); }@ Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }/** * A native method that is implemented by the ' native-lib' native library, * which is packaged with this application. */public static native void path(String []arrays); }
tip:在新版的studio直接鼠标方法jni方法上直接按下Alt+ 回车键直接生产对应实现方法哦.
这里我们在cpp/native-lib.c实现
#include < jni.h> #include " stdio.h" #include " android/log.h" #define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO," jason" ,FORMAT,__VA_ARGS__)#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR," jason" ,FORMAT,__VA_ARGS__)#include " bzip2-1.0.6/bspatch.h" JNIEXPORT void JNICALL Java_com_myself_weather_testjni2_MainActivity_path(JNIEnv *env, jclass tjype, jobjectArray arrays) {jstring a0 = (*env)-> GetObjectArrayElement(env,arrays,0); char *j= (*env)-> GetStringUTFChars(env,a0,NULL); jstring a1 = (*env)-> GetObjectArrayElement(env,arrays,1); char *j1= (*env)-> GetStringUTFChars(env,a1,NULL); jstring a2 = (*env)-> GetObjectArrayElement(env,arrays,2); char *j2= (*env)-> GetStringUTFChars(env,a2,NULL); char * agrs[] = {" patch" ,j,j1,j2}; mybspatch_main(4,agrs); LOGE(" FMY%s" ,j); LOGE(" FMY%s" ,j1); LOGE(" FMY%s" ,j2); }
- 导入bspatch.c导入cpp目录下(记得修改main方法名字和eclipse一样)
- 此时cpp目录
文章图片
- 此时cpp目录
- 修改CmarkList.txt文件
文章图片
- 【最全的增量更新入门 包含linux端和Android】最后合成
package com.myself.weather.testjni2;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import java.io.File;
public class MainActivity extends AppCompatActivity {// Used to load the '
native-lib'
library on application startup.
static {
System.loadLibrary("
native-lib"
);
}@
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv =
(TextView) findViewById(R.id.sample_text);
tv.setOnClickListener(new View.OnClickListener() {
@
Override
public void onClick(View v) {
File oldFile =
new File(Environment.getExternalStorageDirectory(),"
old.zip"
);
File newFile =
new File(Environment.getExternalStorageDirectory(),"
new.zip"
);
File patchFile =
new File(Environment.getExternalStorageDirectory(),"
path.patch"
);
path(new String [] {oldFile.getAbsolutePath(),newFile.getAbsolutePath(),patchFile.getAbsolutePath()});
}
});
}/**
* A native method that is implemented by the '
native-lib'
native library,
* which is packaged with this application.
*/public static native void path(String []arrays);
}
推荐阅读
- Android--利用相机或相册截取用户头像(解决了miui无法截取,以及部分机型拍照无返回Uri)
- (已解决)Eclipse报错(Could not find XXX.apk. 没有Android项目命名. There is no android project named)
- Android-Activity启动流程
- 安卓开源安卓拼图实现,数据驱动,可记录图片位置參数,希望大家有兴趣一起完好!
- 如何在Python中使用Keras和TensorFlow构建垃圾邮件分类器()
- 如何使用Python和Scikit-learn制作语音情感识别器()
- 供数据科学家和机器学习工程师使用的9大Python库合集
- 使用Python与FXCM Broker实现算法交易(详细指南)
- 如何在Python中使用Tensorflow 2和Keras制作图像分类器()