主頁 > 移動端開發 > 使用Python決議并“篡改”MySQL的Binlog

使用Python決議并“篡改”MySQL的Binlog

2020-09-30 22:19:01 移動端開發

文章目錄

  • 前言
  • Binlog的結構
  • 恢復誤洗掉的記錄
  • 找出 Binlog 中的大事務
  • 切割 Binlog 中的大事務
  • 后記

前言

MySQL 的 Binlog 記錄著 MySQL 資料庫的所有變更資訊,了解 Binlog 的結構可以幫助我們決議Binlog,甚至對 Binlog 進行一些修改,或者說是“篡改”,例如實作類似于 Oracle 的 flashback 的功能,恢復誤洗掉的記錄,把 update 的記錄再還原回去等,本文將帶您探討一下這些神奇功能的實作,您會發現比您想象地要簡單得多,本文指的 Binlog 是 ROW 模式的 Binlog,這也是 MySQL 8 里的默認模式,STATEMENT 模式因為使用中有很多限制,現在用地越來越少了,

Binlog的結構

Binlog由事件(event)組成,請注意是事件(event)不是事務(transaction),一個事務可以包含多個事件,事件描述對資料庫的修改內容,
從 MySQL 5 版本開始,Binlog 采用的是 v4 版本,事件的型別根據 MySQL 的內部檔案,有下面36類:

enum Log_event_type { 
  UNKNOWN_EVENT= 0, 
  START_EVENT_V3= 1, 
  QUERY_EVENT= 2, 
  STOP_EVENT= 3, 
  ROTATE_EVENT= 4, 
  INTVAR_EVENT= 5, 
  LOAD_EVENT= 6, 
  SLAVE_EVENT= 7, 
  CREATE_FILE_EVENT= 8, 
  APPEND_BLOCK_EVENT= 9, 
  EXEC_LOAD_EVENT= 10, 
  DELETE_FILE_EVENT= 11, 
  NEW_LOAD_EVENT= 12, 
  RAND_EVENT= 13, 
  USER_VAR_EVENT= 14, 
  FORMAT_DESCRIPTION_EVENT= 15, 
  XID_EVENT= 16, 
  BEGIN_LOAD_QUERY_EVENT= 17, 
  EXECUTE_LOAD_QUERY_EVENT= 18, 
  TABLE_MAP_EVENT = 19, 
  PRE_GA_WRITE_ROWS_EVENT = 20, 
  PRE_GA_UPDATE_ROWS_EVENT = 21, 
  PRE_GA_DELETE_ROWS_EVENT = 22, 
  WRITE_ROWS_EVENT = 23, 
  UPDATE_ROWS_EVENT = 24, 
  DELETE_ROWS_EVENT = 25, 
  INCIDENT_EVENT= 26, 
  HEARTBEAT_LOG_EVENT= 27, 
  IGNORABLE_LOG_EVENT= 28,
  ROWS_QUERY_LOG_EVENT= 29,
  WRITE_ROWS_EVENT = 30,
  UPDATE_ROWS_EVENT = 31,
  DELETE_ROWS_EVENT = 32,
  GTID_LOG_EVENT= 33,
  ANONYMOUS_GTID_LOG_EVENT= 34,
  PREVIOUS_GTIDS_LOG_EVENT= 35, 
  ENUM_END_EVENT 
  /* end marker */ 
};

每個 Binlog 檔案總是以 Format Description Event 作為開始,以 Rotate Event 結束作為結束,我們來看一個 Binlog 的例子:

mysql>  show binlog events in 'scut.000023';
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
| Log_name    | Pos | Event_type     | Server_id | End_log_pos | Info                                                   |
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
| scut.000023 |   4 | Format_desc    |      1024 |         123 | Server ver: 5.7.31-0ubuntu0.16.04.1-log, Binlog ver: 4 |
| scut.000023 | 123 | Previous_gtids |      1024 |         154 |                                                        |
| scut.000023 | 154 | Anonymous_Gtid |      1024 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                   |
| scut.000023 | 219 | Query          |      1024 |         291 | BEGIN                                                  |
| scut.000023 | 291 | Rows_query     |      1024 |         330 | # delete from tt1                                      |
| scut.000023 | 330 | Table_map      |      1024 |         378 | table_id: 111 (test.tt1)                               |
| scut.000023 | 378 | Delete_rows    |      1024 |         434 | table_id: 111 flags: STMT_END_F                        |
| scut.000023 | 434 | Xid            |      1024 |         465 | COMMIT /* xid=216 */                                   |
| scut.000023 | 465 | Rotate         |      1024 |         507 | scut.000024;pos=4                                      |
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
9 rows in set (0.00 sec)

關于“show binlog events”語法顯示的每一列的作用說明如下:

列名說明
Log_name當前事件所在的 binlog 檔案名稱
Pos當前事件的開始位置,每個事件都占用固定的位元組大小,結束位置(End_log_position)減去Pos,就是這個事件占用的位元組數,
Event_type表示事件的型別
Server_id表示產生這個事件的 MySQL server_id
End_log_position下一個事件的開始位置
Info當前事件的描述資訊

每個事件型別的說明可以參考 MySQL 的內部檔案,我們這里說明一下這里遇到的幾個事件型別:

事件名說明
Format_desc是 binlog 檔案的第一個事件,在 Info 列,我們可以看到,其標明了 MySQL Server 的版本是5.7.31, Binlog 版本是4,
Previous_gtids這是表示之前的 Binlog 檔案中,已經執行過的 GTID,需要我們開啟 GTID 選項,這個事件才會有值,
Anonymous_Gtid沒有開啟 GTID 選項時,每個事務開始的事件;
Query是向 Binlog 發生一個陳述句,這里是事務的開始陳述句 begin,
Rows_query記錄SQL,這個事件只有當引數 binlog_rows_query_log_events 為 TRUE 的情況下才會產生,這個引數的默認為值為 FALSE,
Table_map記錄將要被修改的表的結構
Delete_rows從表中洗掉一個記錄
Xid事務 commit 的時候寫入事務 ID
RotateRotate Event是每個Binlog檔案的結束事件,在Info列中,我們看到了其指定了下一個 Binlog檔案的名稱是 mysql-bin.000018,

根據官方檔案,事件(event)資料結構如下:

+=====================================+
| event  | timestamp         0 : 4    |
| header +----------------------------+
|        | type_code         4 : 1    |
|        +----------------------------+
|        | server_id         5 : 4    |
|        +----------------------------+
|        | event_length      9 : 4    |
|        +----------------------------+
|        | next_position    13 : 4    |
|        +----------------------------+
|        | flags            17 : 2    |
|        +----------------------------+
|        | extra_headers    19 : x-19 |
+=====================================+
| event  | fixed part        x : y    |
| data   +----------------------------+
|        | variable part              |
+=====================================+

恢復誤洗掉的記錄

現在我們已經了解了 Binlog 的結構,我們可以試著修改 Binlog 里的資料,例如前面舉例的 Binlog 洗掉了一條記錄,我們可以試著把這條記錄恢復,Binlog 里面有個洗掉行(DELETE_ROWS_EVENT)的事件,就是這個事件洗掉了記錄,這個事件和寫行(WRITE_ROWS_EVENT)的事件的資料結構是完全一樣的, 只是洗掉行事件的型別是32,寫行事件的型別是30,我們把對應的 Binlog 位置的32改成30即可把已經洗掉的記錄再插入回去,從前面的“show binlog events”里面可看到這個 DELETE_ROWS_EVENT 是從位置378開始的,這里的位置就是 Binlog 檔案的實際位置(以位元組為單位),從事件(event)的結構里面可以看到 type_code 是在 event 的第5個位元組,我們寫個 Python 小程式把把第383(378+5=383)位元組改成30即可,當然您也可以用二進制編輯工具來改,下面是這個 Python 小程式的例子:

#! /usr/bin/python3
import sys

if len(sys.argv) != 3:
        print ('Please run chtype.py inputType changedType.')
        sys.exit()

inputType=open(sys.argv[1],"rb")
changedType=open(sys.argv[2],"wb")

changedType.write(inputType.read(382))
changedType.write(chr(30).encode())
inputType.seek(1,1)
while True:
  line = inputType.readline()  
  if not line:
        break
  changedType.write(line)
  
inputType.close()
changedType.close()

我們把原來的 Binlog 和修改后的 Binlog 進行一個對比:
Binlog 修改對比

發現這兩個 Binlog只有一個位元組有區別,也就是 type_code 從32變成了30,注意 Binlog 里面顯示的是16進制的數字,
我們分別應用一下原來的 Binlog 和修改后的 Binlog,看看效果如何?

$ mysql  -e "select * from test.tt1";
$ mysqlbinlog ./scut.000023_ch |mysql
$ mysql  -e "select * from test.tt1";
+---------------------+
| col1                |
+---------------------+
| aaaaaaaaaaaaaaaaaaa |
+---------------------+
$ mysqlbinlog ./scut.000023 |mysql
$ mysql  -e "select * from test.tt1";
$ mysqlbinlog ./scut.000023_ch |mysql
$ mysql  -e "select * from test.tt1";
+---------------------+
| col1                |
+---------------------+
| aaaaaaaaaaaaaaaaaaa |
+---------------------+

我們發現這兩個 Binlog 可以分別把對應的記錄洗掉和插入到 MySQL 資料庫中,這樣我們就成功地實作了類似于 Oracle 的 flashback 功能,

找出 Binlog 中的大事務

由于 ROW 模式的 Binlog 是每一個變更都記錄一條日志,因此一個簡單的 SQL,在 Binlog 里可能會產生一個巨無霸的事務,例如一個不帶 where 的 update 或 delete 陳述句,修改了全表里面的所有記錄,每條記錄都在 Binlog 里面記錄一次,結果是一個巨大的事務記錄,這樣的大事務經常是產生麻煩的根源,我的一個客戶有一次向我抱怨,一個 Binlog 前滾,滾了兩天也沒有動靜,我把那個 Binlog 決議了一下,發現里面有個事務產生了 1.4G 的記錄,修改了66萬條記錄!下面是一個簡單的找出 Binlog 中大事務的 Python 小程式,我們知道用 mysqlbinlog 決議的 Binlog,每個事務都是以BEGIN 開頭,以 COMMIT 結束,我們找出 BENGIN 前面的“# at”的位置,檢查 COMMIT 后面的“# at”位置,這兩個位置相減即可計算出這個事務的大小,下面是這個 Python程式的例子,

$ cat ./checkBigTran.py 
#! /usr/bin/python3
import sys

position=0
beginPosition=0
endPosition=0
maxSize=0
isEnd=0
for line in sys.stdin:
      if line[: 4]=='# at':
          position=int(line[5:])
          if isEnd:
             endPosition=position
             isEnd=0
      if line[: 5]=='BEGIN':
          beginPosition=position
      if line[: 6]=='COMMIT':
          isEnd=1
      if endPosition-beginPosition>maxSize:
          maxBeginPosition= beginPosition
          maxEndPosition=endPosition
          maxSize=endPosition-beginPosition

print("The largest transaction size is %d, the begion position is %d, the end position is %d." % (maxSize,maxBeginPosition,maxEndPosition))

用這個小程式檢查一下可能包含大事務的 Binlog:

$ mysqlbinlog binlog1|./checkBigTran.py 
The largest transaction size is 1468183501, the begion position is 5737766, the end position is 1473921267.

發現里面果然包含了一個1.4G的大事務,

切割 Binlog 中的大事務

對于大的事務, MySQL 會把它分解成多個事件(注意一個是事務TRANSACTION,另一個是事件EVENT),事件的大小由引數 binlog-row-event-max-size 決定,這個引數默認是8K,因此我們可以把若干個事件切割成一個單獨的略小的事務,例如下面這個 Binlog:

mysql> show binlog events in 'scut.000025';
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
| Log_name    | Pos | Event_type     | Server_id | End_log_pos | Info                                                   |
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
| scut.000025 |   4 | Format_desc    |      1024 |         123 | Server ver: 5.7.31-0ubuntu0.16.04.1-log, Binlog ver: 4 |
| scut.000025 | 123 | Previous_gtids |      1024 |         154 |                                                        |
| scut.000025 | 154 | Anonymous_Gtid |      1024 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                   |
| scut.000025 | 219 | Query          |      1024 |         291 | BEGIN                                                  |
| scut.000025 | 291 | Rows_query     |      1024 |         343 | # insert into tt1 values ('1')                         |
| scut.000025 | 343 | Table_map      |      1024 |         391 | table_id: 111 (test.tt1)                               |
| scut.000025 | 391 | Write_rows     |      1024 |         429 | table_id: 111 flags: STMT_END_F                        |
| scut.000025 | 429 | Rows_query     |      1024 |         481 | # insert into tt1 values ('2')                         |
| scut.000025 | 481 | Table_map      |      1024 |         529 | table_id: 111 (test.tt1)                               |
| scut.000025 | 529 | Write_rows     |      1024 |         567 | table_id: 111 flags: STMT_END_F                        |
| scut.000025 | 567 | Xid            |      1024 |         598 | COMMIT /* xid=397 */                                   |
| scut.000025 | 598 | Rotate         |      1024 |         640 | scut.000026;pos=4                                      |
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
12 rows in set (0.01 sec)

這個 Binlog 的兩個 insert 是在一個事務里面完成的,我們可以兩個事務之間插入 xid、Anonymous_Gtid, Query 等三個事件把一個事務切割成兩個事務, Rows_query 這個事件不用插入,這個事件是注釋掉了的,記錄的是執行的 SQL,這個事件只有在引數 binlog_rows_query_log_events 為 on 時才會有,默認是 off ,相應的 Python 程式如下:

# cat splitTran.py 
#! /usr/bin/python3
import sys

if len(sys.argv) != 3:
    print ('Please run splitTrans.py inputBinlog changedBinlog.')
    sys.exit()

inputBinlog=open(sys.argv[1],"rb")
changedBinlog=open(sys.argv[2],"wb")

changedBinlog.write(inputBinlog.read(429))   # read from the head of  input binlog file to the first insert, then write into the changed binlog file.
firstInsert=inputBinlog.tell()
inputBinlog.seek(567,0)  # locate to the xid event
changedBinlog.write(inputBinlog.read(31))  # read from 567 to 598, write xid event, into the changed binlog file.
inputBinlog.seek(154,0)  # locate to the Anonymous_Gtid, Query events.
changedBinlog.write(inputBinlog.read(137))  # read from 154 to 291, write Anonymous_Gtid, Query events into changed binlog file.
inputBinlog.seek(firstInsert)
while True:
      line = inputBinlog.readline()  
      if not line:
           break
      changedBinlog.write(line)
  
inputBinlog.close()
changedBinlog.close()

我們執行這個 Python 程式,生成一個新的 Binlog ,然后把新的 Binlog 應用到 MySQL,

$  ./splitTran.py scut.000025 scut.000025_ch
$ mysqlbinlog scut.000025_ch |mysql
$ 

我們看看執行地效果:


mysql> show binlog events in 'scut.000026';
+-------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------------------------------------------------------------------+
| Log_name    | Pos | Event_type     | Server_id | End_log_pos | Info                                                                                                                               |
+-------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------------------------------------------------------------------+
| scut.000026 |   4 | Format_desc    |      1024 |         123 | Server ver: 5.7.31-0ubuntu0.16.04.1-log, Binlog ver: 4                                                                             |
| scut.000026 | 123 | Previous_gtids |      1024 |         154 |                                                                                                                                    |
| scut.000026 | 154 | Anonymous_Gtid |      1024 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                                                                               |
| scut.000026 | 219 | Query          |      1024 |         287 | BEGIN                                                                                                                              |
| scut.000026 | 287 | Rows_query     |      1024 |         439 | # BINLOG '
EbA7XxMABAAAMAAAAIcBAAAAAG8AAAAAAAEABHRlc3QAA3R0MQAB/gL+QAEYYumN
EbA7Xx4ABAAAJgAAAK0BAAAAAG8AAAAAAAEAAgAB//4BMeeyFcw=
' |
| scut.000026 | 439 | Table_map      |      1024 |         487 | table_id: 111 (test.tt1)                                                                                                           |
| scut.000026 | 487 | Write_rows     |      1024 |         525 | table_id: 111 flags: STMT_END_F                                                                                                    |
| scut.000026 | 525 | Xid            |      1024 |         556 | COMMIT /* xid=425 */                                                                                                               |
| scut.000026 | 556 | Anonymous_Gtid |      1024 |         621 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                                                                               |
| scut.000026 | 621 | Query          |      1024 |         689 | BEGIN                                                                                                                              |
| scut.000026 | 689 | Rows_query     |      1024 |         841 | # BINLOG '
F7A7XxMABAAAMAAAABECAAAAAG8AAAAAAAEABHRlc3QAA3R0MQAB/gL+QAE+WKbj
F7A7Xx4ABAAAJgAAADcCAAAAAG8AAAAAAAEAAgAB//4BMmfP2Zk=
' |
| scut.000026 | 841 | Table_map      |      1024 |         889 | table_id: 111 (test.tt1)                                                                                                           |
| scut.000026 | 889 | Write_rows     |      1024 |         927 | table_id: 111 flags: STMT_END_F                                                                                                    |
| scut.000026 | 927 | Xid            |      1024 |         958 | COMMIT /* xid=432 */                                                                                                               |
+-------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------------------------------------------------------------------+
14 rows in set (0.00 sec)

我們看到兩個 insert 已經分開到兩個事務里面了,

后記

ROW模式下,即使我們只更新了一條記錄的其中某個欄位,也會記錄每個欄位變更前后的值,這個行為是 binlog_row_image 引數控制的,這個引數有3個值,默認為FULL,也就是記錄列的所有修改,即使欄位沒有發生變更也會記錄,這樣我們就可以實作類似 Oracle 的 flashback 的功能,我個人估計 MySQL 未來的版本從可能會基于 Binlog 推出這樣的功能,
了解了 Binlog 的結構,再加上 Python 這把瑞士軍刀,我們還可以實作很多功能,例如我們可以統計哪個表被修改地最多? 我們還可以把 Binlog 切割成一段一段的,然后再重組,可以靈活地進行 MySQL 資料庫的修改和遷移等作業,

姚遠2018 CSDN認證博客專家 10G OCM 12C OCM
Oracle10g,12c OCM; MySQL 5.6,5.7,8.0 OCP;CCNA; EMC Certified; IBM P Certified; RHCE; SQLServer 764; DB2 Certified; TOEIC 890;獲得過兩次國家部級科技進步獎;發明過兩項計算機專利,

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/143394.html

標籤:其他

上一篇:深入oracle索引,磁區

下一篇:MySQL8.0基本操作以及進階操作

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more