【Android】WebDav For Android

最近在写一个云备份功能,参考了一下市面上的软件,发现有一种采用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

原文地址:https://www.cnblogs.com/robotpaul/p/12005045.html