天天看點

Android下最簡單的共享檔案的方法

Android手機的多樣性給了使用者很多選擇,但也造成了開發的難度。舉例來說,連象Storage這樣的最基本的功能也會有意想不到的複雜度。

每個Android手機都有一個Primary external storage, 用來存儲程式資料,以及和其他程式共享檔案。許多程式都需要這個空間來存儲檔案。比如Camera用它來存儲照片,Gmail用它來存儲下載下傳的檔案。

造成問題的是不同手機用不同的硬體來提供這個存儲空間。有的用闆上的Flash,有的用SdCard. 問題就出在SdCard上,SdCard是可以取掉的。有個時候是故意取掉的,有個時候是無意的。一次,我同僚說我們程式出問題,我剛開始看,SdCard在的呀。最後把手機打開,竟然是因為卡沒有完全插進去。從外面是看不出來的。

當然使用者是永遠沒錯的,Dev需要處理沒有SdCard的情形。我們程式裡面帶有一個apk檔案,運作的時候需要調用PackageInstallerActivity來安裝這個apk檔案。但因為這是兩個不一樣的程序,是以我們是把apk檔案拷貝到外部存儲空間上,這樣PackageInstallerActivity才能通路到它。

當我的同僚SdCard沒有全部插進去的時候,這種方式就不能工作了。因為存儲空間不存在了。

花了好幾個小時研究怎樣共享内部的檔案,一直沒找到什麼好方法。Android的Sandbox方式還真是讓共享造成很多麻煩。都開始想做一個ContentProvider了,當然是有點小題大做的味道,但也沒有其他的好辦法。

直到在Context中看到這個。

http://developer.android.com/reference/android/content/Context.html#openFileOutput(java.lang.String, int)

public static final int MODE_WORLD_READABLE

Since: API Level 1
File creation mode: allow all other applications to have read access to the created file.
           

基本上,這可以允許在程式的Sandbox裡建立檔案的時候,允許其他程式通路。

接下來就簡單了。把需要共享的檔案從Resource裡拷貝到程式的私有存儲空間,并且賦予足夠的權限,然後就可以用檔案路徑來通路了。

主要代碼如下

/**
	 * Get the shared file path. The shared file resides in app private storage but it's make world readable.
	 * In the first time, the shared file is copied from raw resource.
	 * @param ctx Context
	 * @return The shared file object.
	 */
	private File getSharedFilePath(Context ctx) {
		File cacheFile = ctx.getFileStreamPath(CACHE_APK);
		if (!cacheFile.exists()) {
			Log.i(TAG, "Copy the file to internal storage for the first time.");
			OutputStream os = null;
			InputStream is = null;
			try {
				is = ctx.getResources().openRawResource(R.raw.nytimes);
				os = ctx.openFileOutput(CACHE_APK, Context.MODE_WORLD_READABLE);
				IOUtils.copy(is, os);
			} catch (FileNotFoundException e) {
				Log.i(TAG, "Shouldn't happen:" + e);
			} catch (IOException e) {
				Log.i(TAG, "Failed to copy:" + e);
			} finally {
				IOUtils.closeSilently(os);
				IOUtils.closeSilently(is);
			}
		}
		return cacheFile;
	}