幾周前在做android彩信資料庫還原時遇到了一個很棘手的問題,就是android的彩信資料庫不向短信資料庫那樣可以友善的用一條insert語句建立一條記錄,而我沒有得到許可去修改android平台的彩信應用的原代碼,是以我不得不另尋它徑。在下面我會盡我可能用盡量簡潔的語言描述整個解決的過程。
1 彩信資料庫
問題是這樣的,我備份了android的彩信資料庫,即mmssms.db檔案,并且希望能成功把彩信部分的資料資訊還原到還原資料庫中。
在mmssms.db中與彩信相關的表有
pdu表: 記錄一條彩信的主要資訊,包括時間,thread_id等;
addr表:記錄一條彩信發送的目的地位址(手機号碼),其中外鍵msg_id映射pdu表的id;
part表:記錄一條彩資訊的附件,文本資訊,基中外鍵mid映射pdu表的id号;
通路pdu表的uri:
public static final uri content_uri = uri.parse(“content://mms”);
通路part表的uri
uri.parse(“content://mms”+pduid+”/part”),
當然你可以了把pduid放到query函數的selection語句中,如
string selection = new string("mid='" + key + "'");//這個key就是pdu裡面的_id。
cursor cur = getcontentresolver().query(uri.parse("content://mms/part"), null, selection, null, null);
通路addr表的uri:
uri.parse(“content://mms”+pduid+”/addr”),同樣也可以用另一種方法
2 還原過程
開始做還原時,我繼承了還原短信資料庫時的思路,用了一個insert語句去插入一條新資料,但可惜的是在pdu表中的thread字段始終不能自動生成,這現象恰好和做普通的短信還原時相反,什麼原因呢?我檢視了android的mms的原代碼,發現原代碼中更本就沒有支援你去插入一條彩信時,它會自動去生成thread字段。我要的可不是簡單的憑空建立一個thread字段喲。在短信資料庫中,同一個聯系人下會在threads表中對應一條thread記錄(我了解成一個組),發給同一個人的資訊和同一個發給你的資訊(包括普通短信與彩信)都會存在同一個組下,一條thread記錄會存儲有多少條這樣的短信與彩信,而pdu的外鍵thread會映射到threads表中的id号中。是以,在還原一條開始不存在的聯系人的彩信時,我需要一個可靠的thread。沒有thread,你是沒有辦法在手機messaging下看到你還原的彩信資訊的,相信我。
在一次偶然測試彩信發送的過程中,我發現當你在編輯一條彩信的過程中,會有一條資訊“converting to multimedia message…”,原來是這樣。 我想你也應該明白了。原來程式本身在存入一條彩信記錄是從普通短信記錄轉換過來的,中間有個過渡。那麼在插入一條新彩信時,我應用同樣的先向sms表中插入一條記錄,當然address要和彩信的addr一緻。這樣,你會得到一個thread記錄。然後再用還原pdu表的資訊,這時thread_id已經知道了。記得要删除我們的臨時短信:)
還沒有完呢,當你在還原part表中的附件資訊時,你會發現你怎麼也沒法使附件的檔案資訊路徑(在_data字段中)與實際的附件檔案一緻,檔案名part_+一串數字,明顯與時間有關。你如果再仔細的分析會發現每次插入新資料,_data字段下的檔案名會自動更新到插入時的時間,而不會管你插入時附給些字段的資料。沒得法,又隻能去看看源代碼了,很快就發現源代碼中的insert函數在插入_data字段時,如果是ct != “application/smil”時,是會以目前時間自動更新_data字段裡的檔案名的,沒有相關的檔案程式會自動建立一個0byte的檔案。我處理方法很簡單,就是插入時你不要去更新_data字段,而是用update它,相信我update沒有自動更新的處理。
整理一下,還原的整個過程如下:
a. 建立thread記錄。在sms表中建立一條普通短信記錄,記得發送的号碼要一緻,建立後再在pdu中建立彩信記錄,記得thread字段要與前面建立得到的一緻。還有記住在完成所有的工作後,要删除sms表中的痕迹。
b. 還原addr表。這應該很簡單。
c. 還原part表。要小心_data字段。在更新_data字段前,記得要先上傳附件檔案到com.android.providers.telephony下的app_parts下。
3 編碼問題
在上傳一個中文的附件時,你會在資料庫中發現是亂碼,這點隻是編碼出現了一小點的轉換,這是不會影響到手機上的messaging程式對彩信的正确顯示。但如果你要在自己的程式中對資料庫中的資料進行處理時,我相信你還是需要知道是會編碼方式在搗亂。android資料庫中是以iso8859-1對中文編碼的,而程式中一般都是用utf-8.是以,你需要用以下方式轉換編碼,
str = new string(str.getbytes("iso8859-1"), "utf-8");
還有個需要注意的地方就是,在logcat中是不能顯示中文的,不要因為在log中看不到中方就誤以為自己的編碼方式是錯誤的!!!
4 權限問題
write_sms "android.permission.write_sms"
read_sms "android.permission.read_sms"
記得權重限。