NDK开发(三):增量更新

编程入门 行业动态 更新时间:2024-10-09 06:31:19

NDK开发(三):<a href=https://www.elefans.com/category/jswz/34/1766904.html style=增量更新"/>

NDK开发(三):增量更新

效果:

版本1:

增量更新后的版本

用到的C库

bsdiff::

bzip2: /

差分包的生成(windows)

  • 将需要的开源文件导入vs

其中jni.h和jni_md.h头文件从系统jdk中获得,这里会出现各种报错请查看【The POSIX name for this item is deprecated. Instead,】【使用了可能未初始化的本地指针变量“xxx”】


创建java项目

  • 创建jni调用java类
package bsdiff;public class BsDiff {/*** 差分* @param oldfile* @param newfile* @param patchfile*/public native static void diff(String oldfile, String newfile, String patchfile);static {System.loadLibrary("bsdiff");}
}
  • 生成.h头文件放进vs项目中
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class bsdiff_BsDiff */#ifndef _Included_bsdiff_BsDiff
#define _Included_bsdiff_BsDiff
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     bsdiff_BsDiff* Method:    diff* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V*/
JNIEXPORT void JNICALL Java_bsdiff_BsDiff_diff(JNIEnv *, jclass, jstring, jstring, jstring);#ifdef __cplusplus
}
#endif
#endif
  • 在bsdiff.cpp文件中调用实现jni方法

    将main方法更改为bsdiff_main方法直接使用

//JNI调用
JNIEXPORT void JNICALL Java_bsdiff_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,NULL);char* newfile = (char*)env->GetStringUTFChars(newfile_jstr, NULL);char* patchfile = (char*)env->GetStringUTFChars(patchfile_jstr, NULL);//参数(第一个参数无效)char *argv[4];argv[0] = (char*)"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);
}
  • 生成解决方案(.dll)放到java项目跟目录下方便使用

  • 调用jni生成差分包
public class ConstantsWin {//路径不能包含中文public static final String OLD_APK_PATH = "C:/Users/Administrator/Desktop/bsdiff/old.apk";public static final String NEW_APK_PATH = "C:/Users/Administrator/Desktop/bsdiff/new.apk";public static final String PATCH_PATH = "C:/Users/Administrator/Desktop/bsdiff/apk.patch";
}
public class Main {public static void main(String[] args) {//得到差分包BsDiff.diff(ConstantsWin.OLD_APK_PATH,ConstantsWin.NEW_APK_PATH,ConstantsWin.PATCH_PATH);}
}


这里就将两个版本的差分包生成出来了!

差分包的合并

  • 创建android项目
  • 将需要的c文件考入项目中

  • 创建native方法
package com.qufu.mergeupdates.utils.jni;public class BsPatch {/*** 合并* @param oldfile* @param newfile* @param patchfile*/public native static void patch(String oldfile,String newfile,String patchfile);static {System.loadLibrary("bspatch");}
}
  • 生成头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_qufu_mergeupdates_utils_jni_BsPatch */#ifndef _Included_com_qufu_mergeupdates_utils_jni_BsPatch
#define _Included_com_qufu_mergeupdates_utils_jni_BsPatch
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_qufu_mergeupdates_utils_jni_BsPatch* Method:    patch* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V*/
JNIEXPORT void JNICALL Java_com_qufu_mergeupdates_utils_jni_BsPatch_patch(JNIEnv *, jclass, jstring, jstring, jstring);#ifdef __cplusplus
}
#endif
#endif
  • 在bapatch.c文件中实现jni方法,同样将main方法改为bspatch_main方法,方便调用
/*** 合并*/
JNIEXPORT void JNICALL Java_com_qufu_mergeupdates_utils_jni_BsPatch_patch(JNIEnv *env, jclass jcls, jstring oldfile_jstr, jstring newfile_jstr,jstring patchfile_jstr) {int argc = 4;char *oldfile = (*env)->GetStringUTFChars(env, oldfile_jstr, NULL);char *newfile = (*env)->GetStringUTFChars(env, newfile_jstr, NULL);char *patchfile = (*env)->GetStringUTFChars(env, patchfile_jstr, NULL);//参数(第一个参数无效)char *argv[4];argv[0]="bspatch";argv[1]=oldfile;argv[2]=newfile;argv[3]=patchfile;bspatch_main(argc,argv);(*env)->ReleaseStringUTFChars(env,oldfile_jstr,oldfile);(*env)->ReleaseStringUTFChars(env,newfile_jstr,newfile);(*env)->ReleaseStringUTFChars(env,patchfile_jstr,patchfile);
}
  • 权限的申请
 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/><uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"tools:ignore="ProtectedPermissions" />
  • 下载并合并
  class ApkUpdataTask extends AsyncTask<Void,Void,Boolean>{@Overrideprotected Boolean doInBackground(Void... voids) {try {//下载差分包File patchFile = DownloadUtils.download(Constants.URL_PATCH_DOWNLOAD);//获取当前apk文件  /data/app/my.apkString oldfile=ApkUtils.getSourceApkPath(MainActivity.this,getPackageName());String newfile=Constants.NEW_APK_PATH;String patchfile=patchFile.getAbsolutePath();//合并得到最新版本的APK文件BsPatch.patch(oldfile,newfile,patchfile);Log.e("huangxiaoguo","oldfile===>"+oldfile);Log.e("huangxiaoguo","newfile===>"+newfile);Log.e("huangxiaoguo","patchfile===>"+patchfile);}catch (Exception e){e.printStackTrace();return false;}return true;}@Overrideprotected void onPostExecute(Boolean result) {super.onPostExecute(result);//安装if (result){Toast.makeText(MainActivity.this,"安装开始",Toast.LENGTH_LONG).show();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {boolean hasInstallPermission = MainActivity.this.getPackageManager().canRequestPackageInstalls();if (!hasInstallPermission) {//跳转至“安装未知应用”权限界面,引导用户开启权限Uri selfPackageUri = Uri.parse("package:" + MainActivity.this.getPackageName());Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, selfPackageUri);startActivityForResult(intent, REQUEST_CODE_UNKNOWN_APP);return;}else {ApkUtils.installApk(MainActivity.this,Constants.NEW_APK_PATH);}}else {ApkUtils.installApk(MainActivity.this,Constants.NEW_APK_PATH);}}}}

android整体代码

  • 工具类
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;import java.io.File;public class ApkUtils {public static boolean isInstalled(Context context, String packageName) {PackageManager pm = context.getPackageManager();boolean installed = false;try {pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);installed = true;} catch (Exception e) {e.printStackTrace();}return installed;}/*** 获取已安装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 filePath*/public static void installApk(Context context,String filePath) {File apkFile = new File(filePath);Intent intent = new Intent(Intent.ACTION_VIEW);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.addCategory(Intent.CATEGORY_DEFAULT);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//7.0intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);Uri contentUri = FileProvider.getUriForFile(context, "com.qufu.mergeupdates.fileProvider", apkFile);intent.setDataAndType(contentUri, "application/vnd.android.package-archive");} else {/*** 正常安装*/intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");}context.startActivity(intent);}
}
import java.io.File;import android.os.Environment;public class Constants {public static final String PATCH_FILE = "apk.patch";public static final String URL_PATCH_DOWNLOAD = "http://192.168.6.17:8080/ndk/bsdiff/"+PATCH_FILE;public static final String SD_CARD = Environment.getExternalStorageDirectory() + File.separator;//新版本apk的目录public static final String NEW_APK_PATH = SD_CARD+"dn_apk_new.apk";}

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.HttpURLConnection;
import java.URL;import android.os.Environment;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;}}
  • jni

public class BsPatch {/*** 合并* @param oldfile* @param newfile* @param patchfile*/public native static void patch(String oldfile,String newfile,String patchfile);static {System.loadLibrary("bspatch");}
}

import android.Manifest;
import android.content.Intent;
import android.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;import com.qufu.mergeupdates.utils.ApkUtils;
import com.qufu.mergeupdates.utils.Constants;
import com.qufu.mergeupdates.utils.DownloadUtils;
import com.qufu.mergeupdates.utils.jni.BsPatch;import java.io.File;
import java.io.StringReader;import tsou.lib_primissions.HxgPermissionFail;
import tsou.lib_primissions.HxgPermissionHelper;
import tsou.lib_primissions.HxgPermissionSuccess;public class MainActivity extends AppCompatActivity {private static final int REQUESE_CODE = 102;private int REQUEST_CODE_UNKNOWN_APP=110;/*** 使用时放在BaseActivity中或BaseFragment中* @param requestCode* @param permissions* @param grantResults*/@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);HxgPermissionHelper.requestPermissionsResult(this, requestCode, permissions);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQUEST_CODE_UNKNOWN_APP) {ApkUtils.installApk(MainActivity.this,Constants.NEW_APK_PATH);}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initPermission();}@HxgPermissionSuccess(requestCode = REQUESE_CODE)private void success() {Toast.makeText(this, "权限授权了", Toast.LENGTH_SHORT).show();new ApkUpdataTask().execute();}@HxgPermissionFail(requestCode = REQUESE_CODE)private void fail() {Toast.makeText(this, "失败了", Toast.LENGTH_SHORT).show();}private void initPermission() {HxgPermissionHelper.with(this).requestCode(REQUESE_CODE).requestPermission( Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE).request();}class ApkUpdataTask extends AsyncTask<Void,Void,Boolean>{@Overrideprotected Boolean doInBackground(Void... voids) {try {//下载差分包File patchFile = DownloadUtils.download(Constants.URL_PATCH_DOWNLOAD);//获取当前apk文件  /data/app/my.apkString oldfile=ApkUtils.getSourceApkPath(MainActivity.this,getPackageName());String newfile=Constants.NEW_APK_PATH;String patchfile=patchFile.getAbsolutePath();//合并得到最新版本的APK文件BsPatch.patch(oldfile,newfile,patchfile);Log.e("huangxiaoguo","oldfile===>"+oldfile);Log.e("huangxiaoguo","newfile===>"+newfile);Log.e("huangxiaoguo","patchfile===>"+patchfile);}catch (Exception e){e.printStackTrace();return false;}return true;}@Overrideprotected void onPostExecute(Boolean result) {super.onPostExecute(result);//安装if (result){Toast.makeText(MainActivity.this,"安装开始",Toast.LENGTH_LONG).show();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {boolean hasInstallPermission = MainActivity.this.getPackageManager().canRequestPackageInstalls();if (!hasInstallPermission) {//跳转至“安装未知应用”权限界面,引导用户开启权限Uri selfPackageUri = Uri.parse("package:" + MainActivity.this.getPackageName());Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, selfPackageUri);startActivityForResult(intent, REQUEST_CODE_UNKNOWN_APP);return;}else {ApkUtils.installApk(MainActivity.this,Constants.NEW_APK_PATH);}}else {ApkUtils.installApk(MainActivity.this,Constants.NEW_APK_PATH);}}}}
}
  • .h头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_qufu_mergeupdates_utils_jni_BsPatch */#ifndef _Included_com_qufu_mergeupdates_utils_jni_BsPatch
#define _Included_com_qufu_mergeupdates_utils_jni_BsPatch
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_qufu_mergeupdates_utils_jni_BsPatch* Method:    patch* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V*/
JNIEXPORT void JNICALL Java_com_qufu_mergeupdates_utils_jni_BsPatch_patch(JNIEnv *, jclass, jstring, jstring, jstring);#ifdef __cplusplus
}
#endif
#endif
  • 合并c代码
/*-* Copyright 2003-2005 Colin Percival* Copyright 2012 Matthew Endsley* All rights reserved** Redistribution and use in source and binary forms, with or without* modification, are permitted providing that the following conditions * are met:* 1. Redistributions of source code must retain the above copyright*    notice, this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright*    notice, this list of conditions and the following disclaimer in the*    documentation and/or other materials provided with the distribution.** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE* ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE* POSSIBILITY OF SUCH DAMAGE.*/#include "com_qufu_mergeupdates_utils_jni_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>static off_t offtin(u_char *buf)
{off_t y;y=buf[7]&0x7F;y=y*256;y+=buf[6];y=y*256;y+=buf[5];y=y*256;y+=buf[4];y=y*256;y+=buf[3];y=y*256;y+=buf[2];y=y*256;y+=buf[1];y=y*256;y+=buf[0];if(buf[7]&0x80) y=-y;return y;
}int bspatch_main(int argc,char * argv[])
{FILE * f, * cpf, * dpf, * epf;BZFILE * cpfbz2, * dpfbz2, * epfbz2;int cbz2err, dbz2err, ebz2err;int fd;ssize_t oldsize,newsize;ssize_t bzctrllen,bzdatalen;u_char header[32],buf[8];u_char *old, *new;off_t oldpos,newpos;off_t ctrl[3];off_t lenread;off_t i;if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);/* Open patch file */if ((f = fopen(argv[3], "r")) == NULL)err(1, "fopen(%s)", argv[3]);/*File format:0	8	"BSDIFF40"8	8	X16	8	Y24	8	sizeof(newfile)32	X	bzip2(control block)32+X	Y	bzip2(diff block)32+X+Y	???	bzip2(extra block)with control block a set of triples (x,y,z) meaning "add x bytesfrom oldfile to x bytes from the diff block; copy y bytes from theextra block; seek forwards in oldfile by z bytes".*//* Read header */if (fread(header, 1, 32, f) < 32) {if (feof(f))errx(1, "Corrupt patch\n");err(1, "fread(%s)", argv[3]);}/* Check for appropriate magic */if (memcmp(header, "BSDIFF40", 8) != 0)errx(1, "Corrupt patch\n");/* Read lengths from header */bzctrllen=offtin(header+8);bzdatalen=offtin(header+16);newsize=offtin(header+24);if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))errx(1,"Corrupt patch\n");/* Close patch file and re-open it via libbzip2 at the right places */if (fclose(f))err(1, "fclose(%s)", argv[3]);if ((cpf = fopen(argv[3], "r")) == NULL)err(1, "fopen(%s)", argv[3]);if (fseeko(cpf, 32, SEEK_SET))err(1, "fseeko(%s, %lld)", argv[3],(long long)32);if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);if ((dpf = fopen(argv[3], "r")) == NULL)err(1, "fopen(%s)", argv[3]);if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))err(1, "fseeko(%s, %lld)", argv[3],(long long)(32 + bzctrllen));if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);if ((epf = fopen(argv[3], "r")) == NULL)err(1, "fopen(%s)", argv[3]);if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))err(1, "fseeko(%s, %lld)", argv[3],(long long)(32 + bzctrllen + bzdatalen));if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);if(((fd=open(argv[1],O_RDONLY,0))<0) ||((oldsize=lseek(fd,0,SEEK_END))==-1) ||((old=malloc(oldsize+1))==NULL) ||(lseek(fd,0,SEEK_SET)!=0) ||(read(fd,old,oldsize)!=oldsize) ||(close(fd)==-1)) err(1,"%s",argv[1]);if((new=malloc(newsize+1))==NULL) err(1,NULL);oldpos=0;newpos=0;while(newpos<newsize) {/* Read control data */for(i=0;i<=2;i++) {lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);if ((lenread < 8) || ((cbz2err != BZ_OK) &&(cbz2err != BZ_STREAM_END)))errx(1, "Corrupt patch\n");ctrl[i]=offtin(buf);};/* Sanity-check */if(newpos+ctrl[0]>newsize)errx(1,"Corrupt patch\n");/* Read diff string */lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);if ((lenread < ctrl[0]) ||((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))errx(1, "Corrupt patch\n");/* Add old data to diff string */for(i=0;i<ctrl[0];i++)if((oldpos+i>=0) && (oldpos+i<oldsize))new[newpos+i]+=old[oldpos+i];/* Adjust pointers */newpos+=ctrl[0];oldpos+=ctrl[0];/* Sanity-check */if(newpos+ctrl[1]>newsize)errx(1,"Corrupt patch\n");/* Read extra string */lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);if ((lenread < ctrl[1]) ||((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))errx(1, "Corrupt patch\n");/* Adjust pointers */newpos+=ctrl[1];oldpos+=ctrl[2];};/* Clean up the bzip2 reads */BZ2_bzReadClose(&cbz2err, cpfbz2);BZ2_bzReadClose(&dbz2err, dpfbz2);BZ2_bzReadClose(&ebz2err, epfbz2);if (fclose(cpf) || fclose(dpf) || fclose(epf))err(1, "fclose(%s)", argv[3]);/* Write the new file */if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||(write(fd,new,newsize)!=newsize) || (close(fd)==-1))err(1,"%s",argv[2]);free(new);free(old);return 0;
}/*** 合并*/
JNIEXPORT void JNICALL Java_com_qufu_mergeupdates_utils_jni_BsPatch_patch(JNIEnv *env, jclass jcls, jstring oldfile_jstr, jstring newfile_jstr,jstring patchfile_jstr) {int argc = 4;char *oldfile = (*env)->GetStringUTFChars(env, oldfile_jstr, NULL);char *newfile = (*env)->GetStringUTFChars(env, newfile_jstr, NULL);char *patchfile = (*env)->GetStringUTFChars(env, patchfile_jstr, NULL);//参数(第一个参数无效)char *argv[4];argv[0]="bspatch";argv[1]=oldfile;argv[2]=newfile;argv[3]=patchfile;bspatch_main(argc,argv);(*env)->ReleaseStringUTFChars(env,oldfile_jstr,oldfile);(*env)->ReleaseStringUTFChars(env,newfile_jstr,newfile);(*env)->ReleaseStringUTFChars(env,patchfile_jstr,patchfile);
}

源码地址::

更多推荐

NDK开发(三):增量更新

本文发布于:2024-02-28 01:26:10,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1767667.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:增量   NDK

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!