還原Android彩信資料庫

l_serein發表於2012-09-19
幾周前在做Android彩信資料庫還原時遇到了一個很棘手的問題,就是Android的彩信資料庫不向簡訊資料庫那樣可以方便的用一條insert語句建立一條記錄,而我沒有得到許可去修改Android平臺的彩信應用的原始碼,所以我不得不另尋它徑。在下面我會盡我可能用盡量簡潔的語言描述整個解決的過程。

彩信資料庫

問題是這樣的,我備份了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欄位始終不能自動生成,這現象恰好和做普通的簡訊還原時相反,什麼原因呢?我檢視了Androidmms的原始碼,發現原始碼中更本就沒有支援你去插入一條彩信時,它會自動去生成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"

記得加許可權。

相關文章