最近在写一个云备份功能,参考了一下市面上的软件,发现有一种采用WebDav协议的云备份成本比较低,故特地研究一下使用。
服务器提供商是使用国内的坚果云,还是非常良心的。
坚果云官网:https://www.jianguoyun.com
注册账号后,点击账户信息,安全选项中即可看到 第三方应用管理
这里需要三个东西,服务器地址、账户、密码(这个密码是你为应用单独开辟的,不是用户密码),具体参考:http://help.jianguoyun.com/?tag=webdav
拿到数据后,我们就可以开始进行安卓开发了。
依赖以及权限设置
因为涉及到网络,所以需要在Manifests中设置联网权限:
<uses-permission android:name="android.permission.INTERNET" />
同时注意安卓9.0以上的网络安全策略,需要单独配置一下:
在res新建一个 network_config.xml
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true" /> </network-security-config>
接着在Manifests的application中配置:
android:networkSecurityConfig="@xml/network__config"
webDav网上的教程不是特别多,一开始找到的是 lookfirst/sardine
该项目是使用的HttpClient且和安卓部分依赖有些冲突,所以不推荐直接使用
后来在github中找到一个移植到安卓的sardine,项目地址
经过测试可以直接使用。
implementation 'com.thegrizzlylabs.sardine-android:sardine-android:0.5'
当然你也可以直接翻到文末查看我提供的对sardine的二次封装库,使用起来更方便。
基础使用方法
请注意:以下所有方法都必须在新线程中进行,且对UI的直接操作要放回主线程进行,可以考虑使用Handler
初始化
Sardine sardine= new OkHttpSardine(); sardine.setCredentials(userName,password);
这里的userName,password即你的用户账号+分配的应用的所属密码
获取目录下所有文件
List<DavResource> resources = null; try { resources = sardine.list("https://dav.jianguoyun.com/dav/");//如果是目录一定别忘记在后面加上一个斜杠 for (DavResource res : resources) { listNames=listNames+res+" "; } } catch (IOException e) { e.printStackTrace(); }
判断路径(或文件)是否存在
//判断文件是否存在 if (sardine.exists("https://dav.jianguoyun.com/dav/file1.jpg")) System.out.println("got here!"); //判断路径是否存在 if (sardine.exists("https://dav.jianguoyun.com/dav/file/")) System.out.println("got here!");
若目录不存在,可以自己创建:
sardine.createDirectory("https://dav.jianguoyun.com/dav/ 目录名称/");
下载文件
InputStream is = sardine.get("https://dav.jianguoyun.com/dav/"+"文件目录"+"afile.jpg");
上传文件
byte[] data = FileUtils.readFileToByteArray(new File("/file/on/disk")); sardine.put("http://yourdavserver.com/adirectory/nameOfFile.jpg", data);
或者使用
InputStream fis = new FileInputStream(new File("/some/file/on/disk.txt")); sardine.put("http://yourdavserver.com/adirectory/nameOfFile.jpg", fis);
节省内存空间
删除文件
sardine.delete("http://yourdavserver.com/adirectory/nameOfFile.jpg");
综合例子
这里给出一个简单的例子,可以把这些代码统一封装成一个类
/** * 同步管理器 * SyncManager(Context context) * getCloudFiles(final Handler handler) 获取文件 * public void upDate(final Handler handler) 更新文件 * */ public class SyncManager { private String serverHostUrl;//WebDav服务器地址,坚果云为:https://dav.jianguoyun.com/dav/ private String userName;//用户名 private String password;//密码 private Sardine sardine; private Context context; private SettingManager settingManager; public SyncManager(Context context){ this.context=context; //初始化设置,主要是获取用户设定的服务器地址、用户名和密码 settingManager=new SettingManager(context); serverHostUrl=settingManager.getUserServer(); userName=settingManager.getUsername(); password=settingManager.getPassword(); //初始化sardine,使用OkHttpSardine进行实例化 sardine=new OkHttpSardine(); } /** * 更新数据(即上传数据) * @param counterEvents 数据源 * @param handler 线程回调 * */ private void updateFiles(List<CounterEvent> counterEvents,Handler handler){ sardine.setCredentials(userName,password);//设置登录账号,登录 //自己规定一种数据格式,这里面我采用的是json Gson gson=new Gson(); String jsons=gson.toJson(counterEvents); //把要上传的数据转成byte数组 byte[] data=jsons.getBytes(); try { //首先判断目标存储路径文件夹存不存在 if(!sardine.exists(serverHostUrl+"pickTime/")){ //若不存在需要创建目录 sardine.createDirectory(serverHostUrl+"pickTime/"); } //存入数据 sardine.put(serverHostUrl+"pickTime/backup.txt",data); //通知主线程进行下一步操作 Message message=new Message(); message.what=1; handler.sendMessage(message); } catch (IOException e) { Message message=new Message(); message.what=-1; message.obj=e; handler.sendMessage(message); Log.d("啥情况",e.toString()); e.printStackTrace(); } } /** * 封装的更新方法 * @param handler 回调 * */ public void upDate(final Handler handler){ if(userName.equals("")||password.equals("")){ Toasty.info(context,"请设置账号",Toasty.LENGTH_SHORT).show(); Intent intent=new Intent(context, SettingActivity.class); context.startActivity(intent); }else { //开启线程进行执行操作 new Thread(new Runnable() { @Override public void run() { updateFiles(Manager.getAllCounterEvents(context),handler); } }).start(); } } /** * 封装的获取文件方法 * @param handler 回调 * */ public void getCloudFiles(final Handler handler){ if(userName.equals("")||password.equals("")){ Toasty.info(context,"请设置账号",Toasty.LENGTH_SHORT).show(); Intent intent=new Intent(context, SettingActivity.class); context.startActivity(intent); }else { Toasty.info(context,"恢复中",Toasty.LENGTH_SHORT).show(); new Thread(new Runnable() { @Override public void run() { getFiles(handler); } }).start(); } } /** * 获取文件 * @param handler 回调 * */ private void getFiles(Handler handler){ sardine.setCredentials(userName,password);//登录。设置账号 try { //拿到输入流 InputStream inputStream=sardine.get(serverHostUrl+"pickTime/backup.txt"); //设置输入缓冲区 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); // 实例化输入流,并获取网页代 String s; // 依次循环,至到读的值为空 StringBuilder sb = new StringBuilder(); while ((s = reader.readLine()) != null) { sb.append(s); } reader.close(); String str = sb.toString(); //TODO 这里放你的处理逻辑,或者由handler传送给相应处理 Message message=new Message(); message.what=2; handler.sendMessage(message); } catch (IOException e) { Message message=new Message(); message.what=-2; message.obj=e; handler.sendMessage(message); e.printStackTrace(); } } }
封装库
我已经把该代码封装成了一个库,可以直接使用:https://github.com/paul623/WebDavSyncerDemo
implementation 'com.paul623.wdsyncer:wdsyncer:0.0.1'
具体功能及实现请查看github