Jack Jiang

          我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
          posts - 497, comments - 13, trackbacks - 0, articles - 1

          1、引言

          特別說明:本文內(nèi)容僅用于即時(shí)通訊技術(shù)研究和學(xué)習(xí)之用,請(qǐng)勿用于非法用途。如本文內(nèi)容有不妥之處,請(qǐng)聯(lián)系JackJiang進(jìn)行處理!

          我司有關(guān)部門為了獲取黑產(chǎn)群的動(dòng)態(tài),有同事潛伏在大量的黑產(chǎn)群(QQ群、微信群)中,干起了無間道的工作。隨著黑產(chǎn)群數(shù)量的激增,同事希望能自動(dòng)獲取黑產(chǎn)群的聊天信息,并交付風(fēng)控引擎進(jìn)行風(fēng)險(xiǎn)評(píng)估。于是,這個(gè)工作就交給我了,是時(shí)候表現(xiàn)一波了……

          針對(duì)同事的需求,分析了一通,總結(jié)一下:

          1)能夠自動(dòng)獲取微信和 QQ群的聊天記錄;

          2)只要文字記錄,圖片和表情包,語音之類的不要;

          3)后臺(tái)自動(dòng)運(yùn)行,非實(shí)時(shí)獲取記錄。

          注:本文讀取聊天記錄的方法只適用于監(jiān)控自己擁有的微信或者QQ ,無法監(jiān)控或者盜取其他人的聊天記錄。本文只寫了如何獲取聊天記錄,服務(wù)器落地程序并不復(fù)雜,不做贅述。寫的倉(cāng)促,有錯(cuò)別字還請(qǐng)見諒。)

          學(xué)習(xí)交流:

          - 即時(shí)通訊開發(fā)交流3群:185926912[推薦]

          - 移動(dòng)端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動(dòng)端IM

          (本文同步發(fā)布于:http://www.52im.net/thread-1992-1-1.html

          2、相關(guān)文章

          即時(shí)通訊網(wǎng)之前整理過微信本地?cái)?shù)據(jù)庫(kù)的讀取和樣本,如有興趣可請(qǐng)往閱讀:

          微信本地?cái)?shù)據(jù)庫(kù)破解版(含iOS、Android),僅供學(xué)習(xí)研究 [附件下載]

          3、準(zhǔn)備工作

          參閱很多相關(guān)的文章之后,對(duì)這個(gè)需求有了大致的想法,開始著手準(zhǔn)備:

          1)需要一個(gè)有root權(quán)限的Android手機(jī),我用的是紅米5(強(qiáng)調(diào)必須已被ROOT);

          2)android的開發(fā)環(huán)境(就是Android Studio那一套啦);

          3)android相關(guān)的開發(fā)經(jīng)驗(yàn)(我是個(gè)PHP,第一次寫Android程序,踩了不少坑)。

          4、獲取微信聊天記錄過程分享

          4.1 著手準(zhǔn)備

          微信的聊天記錄保存在Android系統(tǒng)的:"/data/data/com.tencent.mm/MicroMsg/c5fb89d4729f72c345711cb*/EnMicroMsg.db" 目錄和文件下。

          該文件是加密的數(shù)據(jù)庫(kù)文件,需要用到sqlcipher來打開。密碼為:MD5(手機(jī)的IMEI+微信UIN)的前七位。文件所在的那個(gè)亂碼文件夾的名稱也是一段加密MD5值:MD5('mm'+微信UIN)。微信的UIN存放在微信文件夾“/data/data/com.tencent.mmshared_prefs/system_config_prefs.xml”中。(這個(gè)減號(hào)一定要帶著!)

          另外:即時(shí)通訊網(wǎng)之前整理過微信本地?cái)?shù)據(jù)庫(kù)的樣本,如有興趣可請(qǐng)往下載:《微信本地?cái)?shù)據(jù)庫(kù)破解版(含iOS、Android),僅供學(xué)習(xí)研究 [附件下載]》。

          注意:如果手機(jī)是雙卡雙待,那么會(huì)有兩個(gè)IMEI號(hào),默認(rèn)選擇 IMEI1,如果不行,可以嘗試一下字符串‘1234567890ABCDEF’。早期的微信會(huì)去判定你的IMEI,如果為空 默認(rèn)選擇這個(gè)字符串。

          拿到密碼,就可以打開EnMicroMsg.db了。微信聊天記錄,包括個(gè)人、群組的所有記錄全部存在message這張表里(如下圖所示),就像下面這兩張截圖里展示的一樣。

          (為了方便截圖,此圖截自《微信本地?cái)?shù)據(jù)庫(kù)破解版(含iOS、Android),僅供學(xué)習(xí)研究 [附件下載]》中的樣本)

          (為了方便截圖,此圖截自《微信本地?cái)?shù)據(jù)庫(kù)破解版(含iOS、Android),僅供學(xué)習(xí)研究 [附件下載]》中的樣本)

          4.2 代碼實(shí)現(xiàn)

          第一步,不可能直接去訪問EnMicroMsg.db。因?yàn)闆]有權(quán)限,還要避免和微信本身產(chǎn)生沖突,所以選擇把這個(gè)文件拷貝到自己的項(xiàng)目下:

          oldPath ="/data/data/com.tencent.mm/MicroMsg/c5fb89d4729f72c345711cb**\***/EnMicroMsg.db";

          newPath ="/data/data/com.你的項(xiàng)目/EnMicroMsg.db";

          copyFile(oldPath,newPath);//代碼見 部分源碼

          第二步,拿到文件的密碼:

          String password = (MD5Until.md5("IMEI+微信UIN").substring(0, 7).toLowerCase());

          第三步,打開文件,執(zhí)行SQL:

          SQLiteDatabase.loadLibs(context);

          SQLiteDatabaseHook hook = newSQLiteDatabaseHook() {

              publicvoidpreKey(SQLiteDatabase database) {

              }

              publicvoidpostKey(SQLiteDatabase database) {

                  database.rawExecSQL("PRAGMA cipher_migrate;");//很重要

              }

          };

          SQLiteDatabase db = openDatabase(newPath, password, null, NO_LOCALIZED_COLLATORS, hook);

              longnow = System.currentTimeMillis();

              Log.e("readWxDatabases", "讀取微信數(shù)據(jù)庫(kù):"+ now);

              intcount = 0;

              if(msgId != "0") {

                  String sql = "select * from message";

                  Log.e("sql", sql);

                  Cursor c = db.rawQuery(sql, null);

                  while(c.moveToNext()) {

                      long_id = c.getLong(c.getColumnIndex("msgId"));

                      String content = c.getString(c.getColumnIndex("content"));

                      inttype = c.getInt(c.getColumnIndex("type"));

                      String talker = c.getString(c.getColumnIndex("talker"));

                      longtime = c.getLong(c.getColumnIndex("createTime"));

                      JSONObject tmpJson = handleJson(_id, content, type, talker, time);

                      returnJson.put("data"+ count, tmpJson);

                      count++;

                  }

                  c.close();

                  db.close();

                  Log.e("readWxDatanases", "讀取結(jié)束:"+ System.currentTimeMillis() + ",count:"+ count);

              }

          到此,我們就可以通過自已寫的代碼拿到微信的聊天記錄了,之后可以直接將整理好的JSON通過POST請(qǐng)求發(fā)到服務(wù)器就可以了。(忍不住吐槽:寫服務(wù)器落地程序用了30分鐘,寫上面這一坨花了三四天,還不包括搭建開發(fā)環(huán)境、下載SDK、折騰ADB什么的)。

          5、獲取QQ聊天記錄過程分享

          5.1 說明

          QQ的聊天記錄有點(diǎn)麻煩,他的文件保存在:“/data/data/com.tencent.mobileqq/databases/你的QQ號(hào)碼.db”。

          這個(gè)文件是不加密的,可以直接打開。QQ中群組的聊天記錄是單獨(dú)建表存放的,所有的QQ群信息存放在TroopInfoV2表里,需要對(duì)字段troopuin求MD5,然后找到他的聊天記錄表:mr_troop_" + troopuinMD5 +"_New。

          但是?。吹?#8220;但是”就沒好事。。。)

          問題來了,它的內(nèi)容是加密的,而且加密方法還很復(fù)雜:根據(jù)手機(jī)IMEI循環(huán)逐位異或。具體的我不舉例子了,太麻煩,直接看文章最后的解密方法。

          5.2 代碼實(shí)現(xiàn)

          第一步,還是拷貝數(shù)據(jù)庫(kù)文件:

          final String QQ_old_path = "/data/data/com.tencent.mobileqq/databases/QQ號(hào).db";

          final String QQ_new_path = "/data/data/com.android.saurfang/QQ號(hào).db";

          DataHelp.copyFile(QQ_old_path,QQ_new_path);

          第二步,打開并讀取內(nèi)容:

          SQLiteDatabase.loadLibs(context);

          String password = "";

          SQLiteDatabaseHook hook = newSQLiteDatabaseHook() {

              publicvoidpreKey(SQLiteDatabase database) {}

              publicvoidpostKey(SQLiteDatabase database) {

                  database.rawExecSQL("PRAGMA cipher_migrate;");

              }

          };

           MessageDecode mDecode = newMessageDecode(imid);

          HashMap<String, String> troopInfo = newHashMap<String, String>();

          try{

              SQLiteDatabase db = openDatabase(newPath,password,null, NO_LOCALIZED_COLLATORS,hook);

              longnow = System.currentTimeMillis();

              Log.e("readQQDatabases","讀取QQ數(shù)據(jù)庫(kù):"+now);

              //讀取所有的群信息

              String sql = "select troopuin,troopname from TroopInfoV2 where _id";

              Log.e("sql",sql);

              Cursor c = db.rawQuery(sql,null);

              while(c.moveToNext()){

                  String troopuin = c.getString(c.getColumnIndex("troopuin"));

                  String troopname = c.getString(c.getColumnIndex("troopname"));

                  String name = mDecode.nameDecode(troopname);

                  String uin = mDecode.uinDecode(troopuin);

                  Log.e("readQQDatanases","讀取結(jié)束:"+name);

                  troopInfo.put(uin, name);

              }

              c.close();


              inttroopCount = troopInfo.size();

              Iterator<String> it = troopInfo.keySet().iterator();

              JSONObject json = newJSONObject();

              //遍歷所有的表

              while(troopCount > 0) {

                  try{

                      while(it.hasNext()) {

                          String troopuin = (String)it.next();

                          String troopname = troopInfo.get(troopuin);

                          if(troopuin.length() < 8)

                              continue;

                          String troopuinMD5 = getMD5(troopuin);

                          String troopMsgSql = "select _id,msgData, senderuin, time from mr_troop_"+ troopuinMD5 +"_New";

                          Log.e("sql",troopMsgSql);

                          Cursor  cc = db.rawQuery(troopMsgSql,null);

                          JSONObject tmp = newJSONObject();

                          while(cc.moveToNext()) {

                              long_id = cc.getLong(cc.getColumnIndex("_id"));

                              byte[] msgByte = cc.getBlob(cc.getColumnIndex("msgData"));

                              String ss = mDecode.msgDecode(msgByte);

                              //圖片不保留

                              if(ss.indexOf("jpg") != -1|| ss.indexOf("gif") != -1

                                      || ss.indexOf("png") != -1)

                                  continue;

                              String time = cc.getString(cc.getColumnIndex("time"));

                              String senderuin = cc.getString(cc.getColumnIndex("senderuin"));

                              senderuin  = mDecode.uinDecode(senderuin);

                              JSONObject tmpJson = handleQQJson(_id,ss,senderuin,time);

                              tmp.put(String.valueOf(_id),tmpJson);

                          }

                          troopCount--;

                          cc.close();

                      }

                  } catch(Exception e) {

                      Log.e("e","readWxDatabases"+e.toString());

                  }

              }

              db.close();

          }catch(Exception e){

              Log.e("e","readWxDatabases"+e.toString());

          }

          然后你就可以把信息發(fā)到服務(wù)器落地了(同樣跟微信的記錄上傳一樣,通過你自已寫的代碼發(fā)送到你的服務(wù)端就可以了)。

          6、題外話:一些注意點(diǎn)

          這里還有幾個(gè)需要注意的地方。

          1)最新安卓系統(tǒng)很難寫個(gè)死循環(huán)直接跑了,所以我們需要使用Intent,來開始Service,再通過Service調(diào)用AlarmManager,就像下面的代碼這樣:

          publicclassMainActivity extendsAppCompatActivity {

              privateIntent intent;

              @Override

              protectedvoidonCreate(Bundle savedInstanceState) {

                  super.onCreate(savedInstanceState);

                  setContentView(R.layout.activity\_main);

                  intent = newIntent(this, LongRunningService.class);

                  startService(intent);

              }


              @Override

              protectedvoidonDestroy() {

                  super.onDestroy();

                  stopService(intent);

              }

          }

          然后再創(chuàng)建一個(gè)LongRunningService,在其中調(diào)用AlarmManager:

          AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

          intMinutes = 60*1000; //此處規(guī)定執(zhí)行的間隔時(shí)間

          longtriggerAtTime = SystemClock.elapsedRealtime() + Minutes;

          Intent intent1 = newIntent(this, AlarmReceiver.class);//注入要執(zhí)行的類

          PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent1, 0);

          manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);

          returnsuper.onStartCommand(intent, flags, startId);

          在AlarmReceiver中調(diào)用我們的方法:

          //微信部分

          postWXMsg.readWXDatabase();

          //QQ部分

          postQQMsg.readQQDatabase();

          //再次開啟LongRunningService這個(gè)服務(wù),即可實(shí)現(xiàn)定時(shí)循環(huán)。

          Intent intentNext = newIntent(context, LongRunningService.class);

          context.startService(intentNext);

          2)安卓不允許在主線程里進(jìn)行網(wǎng)絡(luò)連接,可以直接用 retrofit2 來發(fā)送數(shù)據(jù)(或者最簡(jiǎn)單的方法就是用AsyncTask了)。

          3)項(xiàng)目需要授權(quán)網(wǎng)絡(luò)連接(就是在AndroidManifast.xml里加上網(wǎng)絡(luò)權(quán)限申請(qǐng)就是了);

          4)項(xiàng)目需要引入的包:

          implementation files('libs/sqlcipher.jar')

          implementation files('libs/sqlcipher-javadoc.jar')

          implementation 'com.squareup.retrofit2:retrofit:2.0.0'

          implementation 'com.squareup.retrofit2:converter-gson:2.0.0'

          5)如果復(fù)制文件時(shí)失敗,校驗(yàn)文件路徑不存在,多半是因?yàn)槭跈?quán)問題。需要對(duì)數(shù)據(jù)庫(kù)文件授權(quán) 全用戶rwx權(quán)限;

          6)如果服務(wù)端使用MySql數(shù)據(jù)庫(kù)的話,數(shù)據(jù)庫(kù)編碼請(qǐng)用utf8mb4編碼,用來支持Emoji表情。。

          7、我的部分源碼

          (因?yàn)榉N種原因,我不太好直接把源碼貼上來,現(xiàn)把幾個(gè)實(shí)用方法分享出來,可以直接使用。)

          復(fù)制文件的方法:

          /**

            * 復(fù)制單個(gè)文件

            *

            * @param oldPath String 原文件路徑 如:c:/fqf.txt

            * @param newPath String 復(fù)制后路徑 如:f:/fqf.txt

            * @return boolean

            */

           publicstaticbooleancopyFile(String oldPath, String newPath) {

               deleteFolderFile(newPath, true);

               Log.e("copyFile", "time_1:"+ System.currentTimeMillis());

               InputStream inStream = null;

               FileOutputStream fs = null;

               try{

                   intbytesum = 0;

                   intbyteread = 0;

                   File oldfile = newFile(oldPath);

                   Boolean flag = oldfile.exists();

                   Log.e("copyFile", "flag:"+flag );

                   if(oldfile.exists()) { //文件存在時(shí)

                       inStream = newFileInputStream(oldPath); //讀入原文件

                       fs = newFileOutputStream(newPath);

                       byte[] buffer = newbyte[2048];

                       while((byteread = inStream.read(buffer)) != -1) {

                           bytesum += byteread; //字節(jié)數(shù) 文件大小

                           fs.write(buffer, 0, byteread);

                       }

                       Log.e("copyFile", "time_2:"+ System.currentTimeMillis());

                   }

               } catch(Exception e) {

                   System.out.println("復(fù)制單個(gè)文件操作出錯(cuò)");

                   e.printStackTrace();

               } finally{

                   try{

                       if(inStream != null) {

                           inStream.close();

                       }

                       if(fs != null) {

                           fs.close();

                       }

                   } catch(IOException e) {

                       e.printStackTrace();

                   }

               }

               returntrue;

           }


           /**

            * 刪除單個(gè)文件

            *

            * @param filepath

            * @param deleteThisPath

            */

           publicstaticvoiddeleteFolderFile(String filepath, booleandeleteThisPath) {

               if(!TextUtils.isEmpty(filepath)) {

                   try{

                       File file = newFile(filepath);

                       if(file.isDirectory()) {

                           //處理目錄

                           File files[] = file.listFiles();

                           for(inti = 0; i < file.length(); i++) {

                               deleteFolderFile(files[i].getAbsolutePath(), true);

                           }

                       }

                       if(deleteThisPath) {

                           if(!file.isDirectory()) {

                               //刪除文件

                               file.delete();

                           } else{

                               //刪除目錄

                               if(file.listFiles().length == 0) {

                                   file.delete();

                               }

                           }

                       }

                   } catch(Exception e) {

                       e.printStackTrace();

                   }

               }

           }

          MD5方法:

          publicclassMD5Until {

              publicstaticcharHEX_DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',

                      'A', 'B', 'C', 'D', 'E', 'F'};

              //將字符串轉(zhuǎn)化為位

              publicstaticString toHexString(byte[] b){

                  StringBuilder stringBuilder = newStringBuilder(b.length * 2);

                  for(inti = 0; i < b.length; i++) {

                      stringBuilder.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]);

                      stringBuilder.append(HEX_DIGITS[b[i] & 0x0f]);

                  }

                  returnstringBuilder.toString();

              }

              publicstaticString md5(String string){

                  try{

                      MessageDigest digest = java.security.MessageDigest.getInstance("MD5");

                      digest.update(string.getBytes());

                      bytemessageDigest[] = digest.digest();

                      returntoHexString(messageDigest);

                  }catch(NoSuchAlgorithmException e){

                      e.printStackTrace();

                  }

                  return"";

              }

          }

          QQ信息解密方法:

          public class MessageDecode {

              public String imeiID;

              public intimeiLen;

              public MessageDecode(String imeiID)

              {

                  this.imeiID = imeiID;

                  this.imeiLen = imeiID.length();

              }

              public boolean isChinese(bytech) {

                  intres = ch & 0x80;

                  if(res != 0)

                      returntrue;

                  returnfalse;

              }

              public String timeDecode(String time)

              {

                  String datetime = "1970-01-01 08:00:00";

                  SimpleDateFormat sdFormat = newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                  try{

                      longsecond = Long.parseLong(time);

                      Date dt = newDate(second * 1000);

                      datetime = sdFormat.format(dt);

                  } catch(NumberFormatException e) {

                      e.printStackTrace();

                  }

                  returndatetime;

              }

              public String nameDecode(String name)

              {

                  bytenbyte[] = name.getBytes();

                  byteibyte[] = imeiID.getBytes();

                  bytexorName[] = newbyte[nbyte.length];


                  intindex = 0;

                  for(inti = 0; i < nbyte.length; i++) {

                      if(isChinese(nbyte[i])){

                          xorName[i] = nbyte[i];

                          i++;

                          xorName[i] = nbyte[i];

                          i++;

                          xorName[i] = (byte)(nbyte[i] ^ ibyte[index % imeiLen]);

                          index++;

                      } else{

                          xorName[i] = (byte)(nbyte[i] ^ ibyte[index % imeiLen]);

                          index++;

                      }

                  }

                  return new String(xorName);

              }

              public String uinDecode(String uin)

              {

                  byteubyte[] = uin.getBytes();

                  byteibyte[] = imeiID.getBytes();

                  bytexorMsg[] = newbyte[ubyte.length];

                  intindex = 0;

                  for(inti = 0; i < ubyte.length; i++) {

                      xorMsg[i] = (byte)(ubyte[i] ^ ibyte[index % imeiLen]);

                      index++;

                  }

                  returnnewString(xorMsg);

              }


              public String msgDecode(byte[] msg)

              {

                  byteibyte[] = imeiID.getBytes();

                  bytexorMsg[] = newbyte[msg.length];

                  intindex = 0;

                  for(int i = 0; i < msg.length; i++) {

                      xorMsg[i] = (byte)(msg[i] ^ ibyte[index % imeiLen]);

                      index++;

                  }

                  return new String(xorMsg);

              }

          }

          附錄:有關(guān)微信、QQ的技術(shù)文章匯總

          微信朋友圈千億訪問量背后的技術(shù)挑戰(zhàn)和實(shí)踐總結(jié)

          騰訊技術(shù)分享:騰訊是如何大幅降低帶寬和網(wǎng)絡(luò)流量的(圖片壓縮篇)

          騰訊技術(shù)分享:騰訊是如何大幅降低帶寬和網(wǎng)絡(luò)流量的(音視頻技術(shù)篇)

          微信團(tuán)隊(duì)分享:微信移動(dòng)端的全文檢索多音字問題解決方案

          騰訊技術(shù)分享:Android版手機(jī)QQ的緩存監(jiān)控與優(yōu)化實(shí)踐

          微信團(tuán)隊(duì)分享:iOS版微信的高性能通用key-value組件技術(shù)實(shí)踐

          微信團(tuán)隊(duì)分享:iOS版微信是如何防止特殊字符導(dǎo)致的炸群、APP崩潰的?

          騰訊技術(shù)分享:Android手Q的線程死鎖監(jiān)控系統(tǒng)技術(shù)實(shí)踐

          微信團(tuán)隊(duì)原創(chuàng)分享:iOS版微信的內(nèi)存監(jiān)控系統(tǒng)技術(shù)實(shí)踐

          讓互聯(lián)網(wǎng)更快:新一代QUIC協(xié)議在騰訊的技術(shù)實(shí)踐分享

          iOS后臺(tái)喚醒實(shí)戰(zhàn):微信收款到賬語音提醒技術(shù)總結(jié)

          騰訊技術(shù)分享:社交網(wǎng)絡(luò)圖片的帶寬壓縮技術(shù)演進(jìn)之路

          微信團(tuán)隊(duì)分享:視頻圖像的超分辨率技術(shù)原理和應(yīng)用場(chǎng)景

          微信團(tuán)隊(duì)分享:微信每日億次實(shí)時(shí)音視頻聊天背后的技術(shù)解密

          QQ音樂團(tuán)隊(duì)分享:Android中的圖片壓縮技術(shù)詳解(上篇)

          QQ音樂團(tuán)隊(duì)分享:Android中的圖片壓縮技術(shù)詳解(下篇)

          騰訊團(tuán)隊(duì)分享:手機(jī)QQ中的人臉識(shí)別酷炫動(dòng)畫效果實(shí)現(xiàn)詳解

          騰訊團(tuán)隊(duì)分享 :一次手Q聊天界面中圖片顯示bug的追蹤過程分享

          微信團(tuán)隊(duì)分享:微信Android版小視頻編碼填過的那些坑》 

          微信手機(jī)端的本地?cái)?shù)據(jù)全文檢索優(yōu)化之路》 

          企業(yè)微信客戶端中組織架構(gòu)數(shù)據(jù)的同步更新方案優(yōu)化實(shí)戰(zhàn)

          微信團(tuán)隊(duì)披露:微信界面卡死超級(jí)bug“15。。。。”的來龍去脈

          QQ 18年:解密8億月活的QQ后臺(tái)服務(wù)接口隔離技術(shù)

          月活8.89億的超級(jí)IM微信是如何進(jìn)行Android端兼容測(cè)試的

          以手機(jī)QQ為例探討移動(dòng)端IM中的“輕應(yīng)用”

          一篇文章get微信開源移動(dòng)端數(shù)據(jù)庫(kù)組件WCDB的一切!

          微信客戶端團(tuán)隊(duì)負(fù)責(zé)人技術(shù)訪談:如何著手客戶端性能監(jiān)控和優(yōu)化

          微信后臺(tái)基于時(shí)間序的海量數(shù)據(jù)冷熱分級(jí)架構(gòu)設(shè)計(jì)實(shí)踐

          微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信的臃腫之困與模塊化實(shí)踐之路

          微信后臺(tái)團(tuán)隊(duì):微信后臺(tái)異步消息隊(duì)列的優(yōu)化升級(jí)實(shí)踐分享

          微信團(tuán)隊(duì)原創(chuàng)分享:微信客戶端SQLite數(shù)據(jù)庫(kù)損壞修復(fù)實(shí)踐》 

          騰訊原創(chuàng)分享(一):如何大幅提升移動(dòng)網(wǎng)絡(luò)下手機(jī)QQ的圖片傳輸速度和成功率》 

          騰訊原創(chuàng)分享(二):如何大幅壓縮移動(dòng)網(wǎng)絡(luò)下APP的流量消耗(下篇)》 

          騰訊原創(chuàng)分享(三):如何大幅壓縮移動(dòng)網(wǎng)絡(luò)下APP的流量消耗(上篇)》 

          微信Mars:微信內(nèi)部正在使用的網(wǎng)絡(luò)層封裝庫(kù),即將開源》 

          如約而至:微信自用的移動(dòng)端IM網(wǎng)絡(luò)層跨平臺(tái)組件庫(kù)Mars已正式開源》 

          開源libco庫(kù):?jiǎn)螜C(jī)千萬連接、支撐微信8億用戶的后臺(tái)框架基石 [源碼下載]》 

          微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解》 

          微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信后臺(tái)?;顚?shí)戰(zhàn)分享(進(jìn)程保活篇)》 

          微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信后臺(tái)保活實(shí)戰(zhàn)分享(網(wǎng)絡(luò)?;钇?》 

          Android版微信從300KB到30MB的技術(shù)演進(jìn)(PPT講稿) [附件下載]》 

          微信團(tuán)隊(duì)原創(chuàng)分享:Android版微信從300KB到30MB的技術(shù)演進(jìn)》 

          微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(jiǎn)(演講全文)

          微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(jiǎn)(PPT講稿) [附件下載]》 

          如何解讀《微信技術(shù)總監(jiān)談架構(gòu):微信之道——大道至簡(jiǎn)》

          微信海量用戶背后的后臺(tái)系統(tǒng)存儲(chǔ)架構(gòu)(視頻+PPT) [附件下載]

          微信異步化改造實(shí)踐:8億月活、單機(jī)千萬連接背后的后臺(tái)解決方案》 

          微信朋友圈海量技術(shù)之道PPT [附件下載]》 

          微信對(duì)網(wǎng)絡(luò)影響的技術(shù)試驗(yàn)及分析(論文全文)》 

          一份微信后臺(tái)技術(shù)架構(gòu)的總結(jié)性筆記》 

          架構(gòu)之道:3個(gè)程序員成就微信朋友圈日均10億發(fā)布量[有視頻]》 

          快速裂變:見證微信強(qiáng)大后臺(tái)架構(gòu)從0到1的演進(jìn)歷程(一)

          快速裂變:見證微信強(qiáng)大后臺(tái)架構(gòu)從0到1的演進(jìn)歷程(二)》 

          微信團(tuán)隊(duì)原創(chuàng)分享:Android內(nèi)存泄漏監(jiān)控和優(yōu)化技巧總結(jié)》 

          全面總結(jié)iOS版微信升級(jí)iOS9遇到的各種“坑”》 

          微信團(tuán)隊(duì)原創(chuàng)資源混淆工具:讓你的APK立減1M》 

          微信團(tuán)隊(duì)原創(chuàng)Android資源混淆工具:AndResGuard [有源碼]》 

          Android版微信安裝包“減肥”實(shí)戰(zhàn)記錄》 

          iOS版微信安裝包“減肥”實(shí)戰(zhàn)記錄》 

          移動(dòng)端IM實(shí)踐:iOS版微信界面卡頓監(jiān)測(cè)方案》 

          微信“紅包照片”背后的技術(shù)難題》 

          移動(dòng)端IM實(shí)踐:iOS版微信小視頻功能技術(shù)方案實(shí)錄》 

          移動(dòng)端IM實(shí)踐:Android版微信如何大幅提升交互性能(一)

          移動(dòng)端IM實(shí)踐:Android版微信如何大幅提升交互性能(二)

          移動(dòng)端IM實(shí)踐:實(shí)現(xiàn)Android版微信的智能心跳機(jī)制》 

          移動(dòng)端IM實(shí)踐:WhatsApp、Line、微信的心跳策略分析》 

          移動(dòng)端IM實(shí)踐:谷歌消息推送服務(wù)(GCM)研究(來自微信)

          移動(dòng)端IM實(shí)踐:iOS版微信的多設(shè)備字體適配方案探討》 

          信鴿團(tuán)隊(duì)原創(chuàng):一起走過 iOS10 上消息推送(APNS)的坑

          騰訊信鴿技術(shù)分享:百億級(jí)實(shí)時(shí)消息推送的實(shí)戰(zhàn)經(jīng)驗(yàn)

          IPv6技術(shù)詳解:基本概念、應(yīng)用現(xiàn)狀、技術(shù)實(shí)踐(上篇)

          IPv6技術(shù)詳解:基本概念、應(yīng)用現(xiàn)狀、技術(shù)實(shí)踐(下篇)

          騰訊TEG團(tuán)隊(duì)原創(chuàng):基于MySQL的分布式數(shù)據(jù)庫(kù)TDSQL十年鍛造經(jīng)驗(yàn)分享

          微信多媒體團(tuán)隊(duì)訪談:音視頻開發(fā)的學(xué)習(xí)、微信的音視頻技術(shù)和挑戰(zhàn)等

          了解iOS消息推送一文就夠:史上最全iOS Push技術(shù)詳解

          騰訊技術(shù)分享:微信小程序音視頻技術(shù)背后的故事

          騰訊資深架構(gòu)師干貨總結(jié):一文讀懂大型分布式系統(tǒng)設(shè)計(jì)的方方面面

          微信多媒體團(tuán)隊(duì)梁俊斌訪談:聊一聊我所了解的音視頻技術(shù)

          騰訊音視頻實(shí)驗(yàn)室:使用AI黑科技實(shí)現(xiàn)超低碼率的高清實(shí)時(shí)視頻聊天

          騰訊技術(shù)分享:微信小程序音視頻與WebRTC互通的技術(shù)思路和實(shí)踐

          手把手教你讀取Android版微信和手Q的聊天記錄(僅作技術(shù)研究學(xué)習(xí))

          >> 更多同類文章 ……

          (本文同步發(fā)布于:http://www.52im.net/thread-1992-1-1.html



          作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
          出處:http://www.52im.net/space-uid-1.html
          交流:歡迎加入即時(shí)通訊開發(fā)交流群 215891622
          討論:http://www.52im.net/
          Jack Jiang同時(shí)是【原創(chuàng)Java Swing外觀工程BeautyEye】【輕量級(jí)移動(dòng)端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
          本博文 歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處(也可前往 我的52im.net 找到我)。


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯(lián)系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 科技| 玉屏| 和田市| 嫩江县| 禹州市| 泽普县| 花莲市| 乳山市| 阿勒泰市| 乐至县| 隆子县| 盖州市| 莆田市| 灌阳县| 渭南市| 平阳县| 新民市| 德格县| 理塘县| 南投市| 会宁县| 达日县| 从化市| 平阴县| 德惠市| 军事| 营山县| 黎川县| 娄烦县| 天峻县| 什邡市| 濮阳县| 隆化县| 沅陵县| 本溪市| 长沙市| 金秀| 灌南县| 合作市| 稷山县| 海安县|