Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發筆記(一百零九)利用網盤實現雲存儲

Android開發筆記(一百零九)利用網盤實現雲存儲

編輯:關於Android編程

網盤存儲

個人開發者往往沒有自己的後台服務器,但同時又想獲取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,因為該應用在申請時就指定了這個默認路徑,如果使用其他路徑會報沒權限;
    private final static String mbApiKey = "CuOLkaVfoz1zGsqFKDgfvI0h";
    private final static String mbRootPath = "/apps/wp2pcs";
3、app首次運行進行登錄時,要把你的帳號授權給wp2pcs應用,以便創建目錄、讀寫文件等操作;下面是百度pcs的登錄授權頁面截圖
\



百度網盤的代碼調用流程是:先調用BaiduOAuth對象的startOAuth鑒權方法(logout是注銷方法),從返回包中獲取AccessToken,後續的文件讀寫操作會用到這個AccessToken。接著實例化一個AccessToken對象,然後對該對象設置AccessToken,再根據業務要求分別調用相應的方法,常用方法說明如下:
quota : 獲取磁盤空間。返回PCSQuotaResponse對象。
list : 獲取文件/目錄列表。返回PCSListInfoResponse對象。
makeDir : 創建目錄。返回PCSFileInfoResponse對象。
deleteFiles : 刪除文件。返回PCSSimplefiedResponse對象。
downloadFileFromStream : 下載文件。返回PCSSimplefiedResponse對象。
uploadFile : 上傳文件。返回PCSFileInfoResponse對象。
rename : 文件改名。返回PCSFileFromToResponse對象。


下面是app操作百度pcs的頁面截圖
\


下面是使用百度網盤的代碼示例:
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 mFileList = new ArrayList();
	//獲取文件/目錄列表
    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 map_param = new HashMap();
			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 map_param = new HashMap();
		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 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 files = new ArrayList();
		    		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 info = new ArrayList();
		    		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,這裡就不再贅述了。下面是阿裡雲對文件存儲進行基本操作的代碼示例:
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 = "";
    private static final String accessKeySecret = "";
    private static final String testBucket = "";
    
    // 需付費購買存儲空間,才能正常使用上傳、下載、列表等功能
    private static final String uploadFilePath = ""; //上傳的目錄
    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();
            }
        });
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved