Android开发笔记(一百零九)利用网盘实现云存储
来源:互联网 发布:数据库逻辑模型设计图 编辑:程序博客网 时间:2024/05/02 16:28
网盘存储
个人开发者往往没有自己的后台服务器,但同时又想获取app的运行信息,这就要借助于第三方的网络存储(也叫网盘、云盘、微盘等等)。通过让app自动在网盘上存取文件,可以间接实现后台服务器的存储功能,同时开发者也能及时找到app的用户信息。曾几何时,各大公司纷纷推出免费的个人网盘服务,还开放了文件管理api给开发者调用,一时间涌现了网盘提供商的八大金刚:百度网盘、阿里云、华为网盘、腾讯微云、新浪微盘、360云盘、金山快盘、115网盘。可是好景不长,出于盈利、监管等等因素,各大网盘开放平台要么停止免费服务、推出收费服务,要么停止个人服务、推出企业服务,要么保留老用户、不再接受新用户,总之现在开发者已不能无偿使用网盘的sdk集成功能了。要想实现app的云存储,得用点真金白银了。
百度网盘
百度的个人网盘又称pcs(Personal Cloud Storage),百度网盘的存储服务本身是免费的,只是对开发者来说,已经不再接受新应用接入pcs。之前已申请的老应用则不受影响(大约是2015年之前的老应用),所以博主寻寻觅觅,总算找到了一个曲线救国道路,让新开发者也能在app中使用网盘服务。具体方法如下:
1、先注册成为百度用户,并开通个人网盘服务,正常的话访问http://pan.baidu.com/就能看到网盘的管理页面;
2、把代码中的mbApiKey和mbRootPath替换为wp2pcs应用的信息,注意存储路径只能是wp2pcs,因为该应用在申请时就指定了这个默认路径,如果使用其他路径会报没权限;
[java] view plain copy
- private final static String mbApiKey = "CuOLkaVfoz1zGsqFKDgfvI0h";
- private final static String mbRootPath = "/apps/wp2pcs";
百度网盘的代码调用流程是:先调用BaiduOAuth对象的startOAuth鉴权方法(logout是注销方法),从返回包中获取AccessToken,后续的文件读写操作会用到这个AccessToken。接着实例化一个AccessToken对象,然后对该对象设置AccessToken,再根据业务要求分别调用相应的方法,常用方法说明如下:
quota : 获取磁盘空间。返回PCSQuotaResponse对象。
list : 获取文件/目录列表。返回PCSListInfoResponse对象。
makeDir : 创建目录。返回PCSFileInfoResponse对象。
deleteFiles : 删除文件。返回PCSSimplefiedResponse对象。
downloadFileFromStream : 下载文件。返回PCSSimplefiedResponse对象。
uploadFile : 上传文件。返回PCSFileInfoResponse对象。
rename : 文件改名。返回PCSFileFromToResponse对象。
下面是app操作百度pcs的页面截图
下面是使用百度网盘的代码示例:
[java] view plain copy
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.AdapterView.OnItemLongClickListener;
- import android.widget.Button;
- import android.widget.ListView;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.baidu.oauth.BaiduOAuth;
- import com.baidu.oauth.BaiduOAuth.BaiduOAuthResponse;
- import com.baidu.pcs.BaiduPCSActionInfo;
- import com.baidu.pcs.BaiduPCSActionInfo.PCSCommonFileInfo;
- import com.baidu.pcs.BaiduPCSActionInfo.PCSFileFromToInfo;
- import com.baidu.pcs.BaiduPCSActionInfo.PCSFileFromToResponse;
- import com.baidu.pcs.BaiduPCSActionInfo.PCSFileInfoResponse;
- import com.baidu.pcs.BaiduPCSActionInfo.PCSListInfoResponse;
- import com.baidu.pcs.BaiduPCSActionInfo.PCSQuotaResponse;
- import com.baidu.pcs.BaiduPCSActionInfo.PCSSimplefiedResponse;
- import com.baidu.pcs.BaiduPCSClient;
- import com.baidu.pcs.BaiduPCSStatusListener;
- import com.example.exmnetdisk.R;
- import com.example.exmnetdisk.pcs.ConfirmDialogFragment.ConfirmCallbacks;
- import com.example.exmnetdisk.pcs.InputDialogFragment.InputCallbacks;
- public class PCSActivity extends Activity implements OnClickListener
- ,OnItemClickListener,OnItemLongClickListener,ConfirmCallbacks,InputCallbacks {
- private static final String TAG = "PCSActivity";
- private TextView tv_desc;
- private TextView tv_path;
- private ListView lv_content;
- private Button btn_login;
- private Button btn_logout;
- private Button btn_upload;
- private Button btn_rename;
- private Button btn_back;
- private Button btn_create;
- private String mbOauth = null;
- private final static String mbApiKey = "CuOLkaVfoz1zGsqFKDgfvI0h";
- private final static String mbRootPath = "/apps/wp2pcs";
- private String mCurrentPath = mbRootPath;
- private String mLocalPath;
- private Handler mbUiThreadHandler = new Handler();
- private final static String POSITION = "position";
- private final static String OPERATION = "operation";
- private final static String FILEPATH = "file_path";
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_pcs);
- tv_desc = (TextView)findViewById(R.id.tv_desc);
- tv_path = (TextView)findViewById(R.id.tv_path);
- lv_content = (ListView)findViewById(R.id.lv_content);
- lv_content.setOnItemClickListener(this);
- lv_content.setOnItemLongClickListener(this);
- btn_login = (Button)findViewById(R.id.btn_login);
- btn_logout = (Button)findViewById(R.id.btn_logout);
- btn_upload = (Button)findViewById(R.id.btn_upload);
- btn_rename = (Button)findViewById(R.id.btn_rename);
- btn_back = (Button)findViewById(R.id.btn_back);
- btn_create = (Button)findViewById(R.id.btn_create);
- btn_login.setOnClickListener(this);
- btn_logout.setOnClickListener(this);
- btn_upload.setOnClickListener(this);
- btn_rename.setOnClickListener(this);
- btn_back.setOnClickListener(this);
- btn_create.setOnClickListener(this);
- mLocalPath = Environment.getExternalStorageDirectory().toString()+"/Download";
- }
- @Override
- public void onClick(View v) {
- if (v.getId() == R.id.btn_login) {
- login();
- } else if (v.getId() == R.id.btn_logout) {
- logout();
- } else if (v.getId() == R.id.btn_upload) {
- upload("2.txt");
- } else if (v.getId() == R.id.btn_rename) {
- rename();
- } else if (v.getId() == R.id.btn_back) {
- if (null != mbOauth) {
- if (mCurrentPath.equals(mbRootPath)) {
- showTip("当前已是根目录");
- } else {
- mCurrentPath = mCurrentPath.substring(0, mCurrentPath.lastIndexOf("/"));
- getList(mCurrentPath);
- }
- }
- } else if (v.getId() == R.id.btn_create) {
- InputDialogFragment dialog = InputDialogFragment.newInstance("请输入目录名称");
- String fragTag = getResources().getString(R.string.app_name);
- dialog.show(getFragmentManager(), fragTag);
- }
- }
- private void showTip(String message) {
- Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
- }
- //登录
- private void login() {
- BaiduOAuth oauthClient = new BaiduOAuth();
- oauthClient.startOAuth(this, mbApiKey, new String[]{"basic", "netdisk"}, new BaiduOAuth.OAuthListener() {
- @Override
- public void onException(String msg) {
- showTip("Login failed " + msg);
- }
- @Override
- public void onComplete(BaiduOAuthResponse response) {
- if (null != response) {
- mbOauth = response.getAccessToken();
- showTip("Token: " + mbOauth + " User name:" + response.getUserName());
- tv_desc.setText("当前登录用户是"+response.getUserName()+",token为"+mbOauth);
- getQuota();
- getList(mbRootPath);
- }
- }
- @Override
- public void onCancel() {
- showTip("Login cancelled");
- }
- });
- }
- //获取磁盘空间
- private void getQuota() {
- if (null != mbOauth) {
- Thread workThread = new Thread(new Runnable() {
- @Override
- public void run() {
- BaiduPCSClient api = new BaiduPCSClient();
- api.setAccessToken(mbOauth);
- final PCSQuotaResponse info = api.quota();
- mbUiThreadHandler.post(new Runnable() {
- public void run() {
- if (null != info) {
- if (0 == info.status.errorCode) {
- showTip("Quota :" + info.total + " used: " + info.used);
- tv_desc.setText(tv_desc.getText()+"\n网盘总容量是"+info.total/1024/1024+"M,已经使用"+info.used/1024/1024+"M.");
- } else {
- showTip("Quota failed: " + info.status.errorCode + " " + info.status.message);
- }
- }
- }
- });
- }
- });
- workThread.start();
- }
- }
- //注销
- private void logout() {
- if (null != mbOauth) {
- Thread workThread = new Thread(new Runnable() {
- @Override
- public void run() {
- BaiduOAuth oauth = new BaiduOAuth();
- final boolean ret = oauth.logout(mbOauth);
- mbUiThreadHandler.post(new Runnable() {
- @Override
- public void run() {
- showTip("Logout " + ret);
- }
- });
- }
- });
- workThread.start();
- }
- }
- private List<PCSCommonFileInfo> mFileList = new ArrayList<PCSCommonFileInfo>();
- //获取文件/目录列表
- private void getList(final String path) {
- if (null != mbOauth) {
- Thread workThread = new Thread(new Runnable() {
- @Override
- public void run() {
- BaiduPCSClient api = new BaiduPCSClient();
- api.setAccessToken(mbOauth);
- final PCSListInfoResponse ret = api.list(path, "name", "asc");
- mbUiThreadHandler.post(new Runnable() {
- public void run() {
- if (ret.status.errorCode == 0) {
- mFileList.clear();
- mFileList = ret.list;
- FileListAdapter adapter = new FileListAdapter(getApplicationContext(), mFileList);
- lv_content.setAdapter(adapter);
- tv_path.setText("当前目录是"+mCurrentPath);
- } else {
- tv_path.setText("获取目录"+mCurrentPath+"失败,原因是"+ret.status.message);
- }
- }
- });
- }
- });
- workThread.start();
- }
- }
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- PCSCommonFileInfo file = mFileList.get(position);
- if (file.isDir == true) {
- mCurrentPath = file.path;
- showTip("您点击了目录"+mCurrentPath);
- getList(mCurrentPath);
- } else {
- ConfirmDialogFragment fsf = ConfirmDialogFragment.newInstance(
- R.drawable.ic_launcher, "下载确认", "是否下载文件"+file.path+"?");
- Map<String, Object> map_param = new HashMap<String, Object>();
- map_param.put(OPERATION, "download");
- map_param.put(POSITION, position);
- map_param.put(FILEPATH, file.path);
- fsf.setParam(map_param);
- fsf.show(getFragmentManager(), "");
- }
- }
- @Override
- public boolean onItemLongClick(AdapterView<?> parent, View view,
- int position, long id) {
- PCSCommonFileInfo file = mFileList.get(position);
- String desc = String.format("是否删除%s%s?", file.isDir?"目录":"文件", file.path);
- ConfirmDialogFragment fsf = ConfirmDialogFragment.newInstance(
- R.drawable.ic_launcher, "删除确认", desc);
- Map<String, Object> map_param = new HashMap<String, Object>();
- map_param.put(OPERATION, "delete");
- map_param.put(POSITION, position);
- map_param.put(FILEPATH, file.path);
- fsf.setParam(map_param);
- fsf.show(getFragmentManager(), "");
- return true;
- }
- @Override
- public void onConfirmSelect(Map<String, Object> map_param) {
- String operation = (String) map_param.get(OPERATION);
- if (operation.equals("delete")) {
- int position = (Integer) map_param.get(POSITION);
- PCSCommonFileInfo file = mFileList.get(position);
- deletePCSFile(file.path);
- } else if (operation.equals("download")) {
- String file = (String) map_param.get(FILEPATH);
- download(file);
- }
- }
- @Override
- public void onInput(String dir) {
- createDir(dir);
- }
- //创建目录
- private void createDir(final String dir) {
- if (null != mbOauth) {
- Thread workThread = new Thread(new Runnable() {
- @Override
- public void run() {
- BaiduPCSClient api = new BaiduPCSClient();
- api.setAccessToken(mbOauth);
- String path = mCurrentPath + "/" + dir;
- final PCSFileInfoResponse ret = api.makeDir(path);
- mbUiThreadHandler.post(new Runnable() {
- public void run() {
- showTip("Mkdir: " + ret.status.errorCode + " " + ret.status.message);
- getList(mCurrentPath);
- }
- });
- }
- });
- workThread.start();
- }
- }
- //删除文件。注意不能用deleteFile这个函数名,因为deleteFile在ContextWrapper类中已经定义
- private void deletePCSFile(final String file_path) {
- if (null != mbOauth) {
- Thread workThread = new Thread(new Runnable() {
- @Override
- public void run() {
- BaiduPCSClient api = new BaiduPCSClient();
- api.setAccessToken(mbOauth);
- List<String> files = new ArrayList<String>();
- files.add(file_path);
- final PCSSimplefiedResponse ret = api.deleteFiles(files);
- mbUiThreadHandler.post(new Runnable() {
- public void run() {
- showTip("Delete files: " + ret.errorCode + " " + ret.message);
- getList(mCurrentPath);
- }
- });
- }
- });
- workThread.start();
- }
- }
- private BaiduPCSStatusListener mStatusListener = new BaiduPCSStatusListener() {
- @Override
- public void onProgress(long bytes, long total) {
- final long bs = bytes;
- final long tl = total;
- mbUiThreadHandler.post(new Runnable() {
- public void run() {
- showTip("total: " + tl + " loaded:" + bs);
- }
- });
- }
- @Override
- public long progressInterval() {
- return 500;
- }
- };
- //下载文件
- private void download(final String file) {
- if (null != mbOauth) {
- final String local_file = String.format("%s/%s", mLocalPath, file.substring(1+file.lastIndexOf("/")));
- Thread workThread = new Thread(new Runnable() {
- @Override
- public void run() {
- BaiduPCSClient api = new BaiduPCSClient();
- api.setAccessToken(mbOauth);
- final PCSSimplefiedResponse ret = api.downloadFileFromStream(file, local_file, mStatusListener);
- mbUiThreadHandler.post(new Runnable() {
- public void run() {
- Log.d(TAG, "Download files: " + ret.errorCode + " " + ret.message);
- showTip("download: " + ret.errorCode + " " + ret.message);
- }
- });
- }
- });
- workThread.start();
- }
- }
- // 上传文件
- private void upload(String file) {
- if (null != mbOauth) {
- final String local_file = String.format("%s/%s", mLocalPath, file);
- final String remote_file = String.format("%s/%s", mCurrentPath, file);
- Thread workThread = new Thread(new Runnable() {
- @Override
- public void run() {
- BaiduPCSClient api = new BaiduPCSClient();
- api.setAccessToken(mbOauth);
- final PCSFileInfoResponse response = api.uploadFile(local_file, remote_file, mStatusListener);
- mbUiThreadHandler.post(new Runnable() {
- public void run() {
- showTip("upload: " + response.status.errorCode + " " + response.status.message + " " + response.commonFileInfo.blockList);
- getList(mCurrentPath);
- }
- });
- }
- });
- workThread.start();
- }
- }
- //文件改名
- private void rename() {
- if (null != mbOauth) {
- Thread workThread = new Thread(new Runnable() {
- @Override
- public void run() {
- BaiduPCSClient api = new BaiduPCSClient();
- api.setAccessToken(mbOauth);
- List<PCSFileFromToInfo> info = new ArrayList<PCSFileFromToInfo>();
- PCSFileFromToInfo data1 = new PCSFileFromToInfo();
- data1.from = mCurrentPath + "/2.txt";
- data1.to = "1.txt";
- info.add(data1);
- Log.d(TAG, "from="+data1.from+",to="+data1.to);
- final PCSFileFromToResponse ret = api.rename(info);
- mbUiThreadHandler.post(new Runnable() {
- public void run() {
- showTip("Rename: " + ret.status.errorCode + " " + ret.status.message);
- getList(mCurrentPath);
- }
- });
- }
- });
- workThread.start();
- }
- }
- }
阿里云
阿里云的存储服务又称oss(Online Storage Service),现只提供收费服务,最经济的是40G空间半年5元,或一年9元,个人开发者的app有一定用户量时可以考虑购买。阿里云的sdk的集成比较简单,官方也有提供demo,这里就不再赘述了。下面是阿里云对文件存储进行基本操作的代码示例:
[java] view plain copy
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.Button;
- import com.alibaba.sdk.android.oss.ClientConfiguration;
- import com.alibaba.sdk.android.oss.OSS;
- import com.alibaba.sdk.android.oss.OSSClient;
- import com.alibaba.sdk.android.oss.common.OSSLog;
- import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
- import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider;
- import com.example.exmnetdisk.R;
- public class AliyunActivity extends Activity {
- private OSS oss;
- // 以下字段为注册账号并开通oss服务后由阿里云自动分配
- private static final String endpoint = "http://oss-cn-shanghai.aliyuncs.com";
- private static final String accessKeyId = "<accessKeyId>";
- private static final String accessKeySecret = "<accessKeySecret>";
- private static final String testBucket = "<testBucket>";
- // 需付费购买存储空间,才能正常使用上传、下载、列表等功能
- private static final String uploadFilePath = "<upload_file_path>"; //上传的目录
- private static final String uploadObject = "sampleObject"; //上传的文件
- private static final String downloadObject = "sampleObject"; //下载的文件
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_aliyun);
- OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(accessKeyId, accessKeySecret);
- ClientConfiguration conf = new ClientConfiguration();
- conf.setConnectionTimeout(15 * 1000); // 连接超时,默认15秒
- conf.setSocketTimeout(15 * 1000); // socket超时,默认15秒
- conf.setMaxConcurrentRequest(5); // 最大并发请求书,默认5个
- conf.setMaxErrorRetry(2); // 失败后最大重试次数,默认2次
- OSSLog.enableLog();
- oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider, conf);
- // 上传
- Button upload = (Button) findViewById(R.id.upload);
- upload.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- new PutObjectSamples(oss, testBucket, uploadObject, uploadFilePath).asyncPutObjectFromLocalFile();
- }
- }).start();
- }
- });
- // 下载
- Button download = (Button) findViewById(R.id.download);
- download.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- new GetObjectSamples(oss, testBucket, downloadObject).asyncGetObjectSample();
- }
- }).start();
- }
- });
- // 罗列
- Button list = (Button) findViewById(R.id.list);
- list.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- new ListObjectsSamples(oss, testBucket).asyncListObjectsWithPrefix();
- }
- }).start();
- }
- });
- // 管理
- Button manage = (Button) findViewById(R.id.manage);
- manage.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- new ManageObjectSamples(oss, testBucket, uploadObject).headObject();
- }
- }).start();
- }
- });
- // 分块上传
- Button multipart = (Button) findViewById(R.id.multipart);
- multipart.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- new MultipartUploadSamples(oss, testBucket, uploadObject, uploadFilePath).multipartUpload();
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- }).start();
- }
- });
- // 断点续传
- Button resumable = (Button) findViewById(R.id.resumable);
- resumable.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- new ResuambleUploadSamples(oss, testBucket, uploadObject, uploadFilePath).resumableUpload();
- }
- }).start();
- }
- });
- // 签名URL
- Button sign = (Button) findViewById(R.id.sign);
- sign.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- new SignURLSamples(oss, testBucket, uploadObject, uploadFilePath).presignConstrainedURL();
- }
- }).start();
- }
- });
- // bucket管理
- Button bucket = (Button) findViewById(R.id.bucket);
- bucket.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- new ManageBucketSamples(oss, testBucket, uploadFilePath).deleteNotEmptyBucket();
- }
- }).start();
- }
- });
- }
- }
点此查看Android开发笔记的完整目录
0 0
- Android开发笔记(一百零九)利用网盘实现云存储
- Android开发笔记(一百零九)利用网盘实现云存储
- Android开发笔记(一百零一)滑出式菜单
- Android开发笔记(一百零二)统计图表
- Android开发笔记(一百零四)消息推送SDK
- Android开发笔记(一百零五)社会化分享SDK
- Android开发笔记(一百零五)社会化分享SDK
- Android开发笔记(一百零六)支付缴费SDK
- Android开发笔记(一百零七)统计分析SDK
- Android开发笔记(一百零八)智能语音
- Android开发笔记(一百零六)支付缴费SDK
- Android开发笔记(一百零六)支付缴费SDK
- Android开发笔记(一百零六)支付缴费SDK
- Android开发笔记(一百零五)社会化分享SDK
- Android开发笔记(一百零三)地图与定位SDK
- Android开发笔记(一百四十八)自定义输入法软键盘
- Android开发笔记(一百)折叠式列表
- 问题一百零九:正整数解(2)
- Execution failed for task ':callbacktest:clean'
- UIScrollViewDelegate详解
- C/C++ 关于如何读写ini配置文件 (小结)
- MAPinAnnotationView 和MAAnnotationView 区别 和自定义大头针
- 分组统计查询
- Android开发笔记(一百零九)利用网盘实现云存储
- Python 模块之Logging(四)——常用handlers的使用
- Exoplayer解析hls流分析之一
- Angular_ng-repeat中的问题
- 天涯芳草无归路
- mysql 5.6中的时间类型的新精度
- HTML的学习(第2篇)
- Scrapy入门使用
- 【思维导图入门】基本操作