日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android nio debug模式正常 release包crash_Flutter包大小治理上的探索与实践

發布時間:2023/12/13 编程问答 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android nio debug模式正常 release包crash_Flutter包大小治理上的探索与实践 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Flutter作為一種全新的響應式、跨平臺、高性能的移動開發框架,在性能、穩定性和多端體驗一致上都有著較好的表現,自開源以來,已經受到越來越多開發者的喜愛。

但是,Flutter的引入往往帶來包體積的增大,給很多研發團隊帶來了很大的困擾。美團外賣前端團隊對Flutter的包大小問題進行了調研和實踐,設計并實現了一套基于動態下發的包大小優化方案,希望對從事Flutter開發相關的同學能夠帶來一些啟發或者幫助。

一、背景

隨著Flutter框架的不斷發展和完善,業內越來越多的團隊開始嘗試并落地Flutter技術。不過在實踐過程中我們發現,Flutter的接入會給現有的應用帶來比較明顯的包體積增加。不論是在Android還是在iOS平臺上,僅僅是接入一個Flutter Demo頁面,包體積至少要增加5M,這對于那些包大小敏感的應用來說其實是很難接受的。

對于包大小問題,Flutter官方也在持續跟進優化:

  • Flutter V1.2 開始支持Android App Bundles,支持Dynamic Module下發。
  • Flutter V1.12 優化了2.6% Android平臺Hello World App大小(3.8M -> 3.7M)。
  • Flutter V1.17 通過優化Dart PC Offset存儲以減少StackMap大小等多個手段,再次優化了產物大小,實現18.5%的縮減。
  • Flutter V1.20 通過Icon font tree shaking移除未用到的icon fonts,進一步優化了應用大小。

除了Flutter SDK內部或Dart實現的優化,我們是否還有進一步優化的空間呢?答案是肯定的。為了幫助業務方更好的接入和落地Flutter技術,MTFlutter團隊對Flutter的包大小問題進行了調研和實踐,設計并實現了一套基于動態下發的包大小優化方案,瘦身效果也非常可觀。這里分享給大家,希望對大家能有所幫助或者啟發。

二、Flutter包大小問題分析

在Flutter官方的優化文檔中,提到了減少應用尺寸的方法:在V1.16.2及以上使用—split-debug-info選項(可以分離出debug info);移除無用資源,減少從庫中帶入的資源,控制適配的屏幕尺寸,壓縮圖片文件。這些措施比較直接并容易理解,但為了探索進一步瘦身空間并讓大家更好的理解技術方案,我們先從了解Flutter的產物構成開始,然后再一步步分析有哪些可行的方案。

2.1 Flutter產物介紹

我們首先以官方的Demo為例,介紹一下Flutter的產物構成及各部分占比。不同Flutter版本以及打包模式下,產物有所不同,本文均以Flutter 1.9 Release模式下的產物為準。

2.1.1 iOS側Flutter產物

圖1 Flutter iOS 產物組成示意圖

iOS側的Flutter產物主要由四部分組成(info.plist 比較小,對包體積的影響可忽略,這里不作為重點介紹),表格1中列出了各部分的詳細信息。

表1 Flutter產物組成

2.1.2 Android側Flutter產物

圖2 Flutter Android 產物組成示意圖

Android側的Flutter產物總共5.16MB,由四部分組成,表格2中列出了各部分的詳細信息。

表2 Flutter Android產物組成

2.1.3 各部分產物的變化趨勢

無論是Android還是iOS,Flutter的產物大體可以分為三部分:

  • Flutter引擎,該部分大小固定不變,但初始占比較高。
  • Flutter業務與框架,該部分大小隨著Flutter業務代碼的增多而逐漸增加。它是這樣的一個曲線:初始增長速度極快,隨著代碼增多,增長速度逐漸減緩,最終趨近線性增長。原因是Flutter有一個Tree Shaking機制,從Main方法開始,逐級引用,最終沒有被引用的代碼,比如類和函數都會被裁剪掉。一開始引入Flutter之后隨便寫一個業務,就會大量用到Flutter/Dart SDK代碼,這樣初期Flutter包體積極速增加,但是過了一個臨界點,用戶包體積的增加就基本取決于Flutter業務代碼增量,不會增長得太快。
  • Flutter資源,該部分初始占比較小,后期增長主要取決于用到的本地圖片資源的多少,增長趨勢與資源多少成正比。
  • 下圖3展示了Flutter各資源變化的趨勢:

    圖3 Flutter各資源大小變化的趨勢圖

    2.2 不同優化思路分析

    上面我們對Flutter產物進行了分析,接下來看一下官方提供的優化思路如何應用于Flutter產物,以及對應的困難與收益如何。

    1. 刪減法

    Flutter引擎中包括了Dart、skia、boringssl、icu、libpng等多個模塊,其中Dart和skia是必須的,其他模塊如果用不到倒是可以考慮裁掉,能夠帶來幾百k的瘦身收益。業務方可以根據業務訴求自定義裁剪。

    Flutter業務產物,因為Flutter的Tree Shaking機制,該部分產物從代碼的角度已經是精簡過的,要想繼續精簡只能從業務的角度去分析。

    Flutter資源中占比較多的一般是圖片,對于圖片可以根據業務場景,適當降低圖片分辨率,或者考慮替換為網絡圖片。

    2. 壓縮法

    因為無論是Android還是iOS,安裝包本身已經是壓縮包了,對Flutter產物再次壓縮的收益很低,所以該方法并不適用。

    3. 動態下發

    對于靜態資源,理論上是Android和iOS都可以做到動態下發。而對于代碼邏輯部分的編譯產物,在Android平臺支持可執行產物的動態加載,iOS平臺則不允許執行動態下發的機器指令。

    經過上面的分析可以發現,除了刪減、壓縮,對所有業務適用、可行且收益明顯的進一步優化空間重點在于動態下發了。能夠動態下發的部分越多,包大小的收益越大。因此我們決定從動態下發入手來設計一套Flutter包大小優化方案。

    三、基于動態下發的Flutter包大小優化方案

    我們在Android和iOS上實現的包大小優化方案有所不同,區別在于Android側可以做到so和Flutter資源的全部動態下發,而iOS側由于系統限制無法動態下發可執行產物,所以需要對產物的組成和其加載邏輯進行分析,將其中非必須和動態鏈接庫一起加載的部分進行動態下發、運行時加載。

    當將產物動態下發后,還需要對引擎的初始化流程做修改,這樣才能保證產物的正常加載。由于兩端技術棧的不同,在很多具體實現上都采用了不同的方式,下面就分別來介紹下兩端的方案。

    3.1 iOS側方案

    在iOS平臺上,由于系統的限制無法實現在運行時加載并運行可執行文件,而在上文產物介紹中可以看到,占比較高的App及Flutter這兩個均是可執行文件,理論上是不能進行動態下發的,實際上對于Flutter可執行文件我們能做的確實不多,但對于App這個可執行文件,其內部組成的四個模塊并不是在鏈接時都必須存在的,可以考慮部分移出,進而來實現包體積的縮減。

    因此,在該部分我們首先介紹Flutter產物的生成和加載的流程,通過對流程細節的分析來挖掘出產物可以被拆分出動態下發的部分,然后基于實現原理來設計實現工程化的方案。

    3.1.1 實現原理簡析

    為了實現App的拆分,我們需要了解下App.framework是怎樣生成以及各部分資源時如何加載的。如下圖4所示,Dart代碼會使用gen_snapshot工具來編譯成.S文件,然后通過xcrun工具來進行匯編和鏈接最終生成App.framework。其中gen_snapshot是Dart編譯器,采用了Tree Shaking等技術,用于生成匯編形式的機器代碼。

    圖4 App.framework生成流程示意圖

    產物加載流程:

    圖5 Flutter產物加載流程圖

    如上圖5所示,Flutter engine在初始化時會從根據 FlutterDartProject 的settings中配置資源路徑來加載可執行文件(App)、flutter_assets等資源,具體settings的相關配置如下:

    //?settings{...??//?snapshot?文件地址或內存地址??std::string?vm_snapshot_data_path;????MappingCallback?vm_snapshot_data;??std::string?vm_snapshot_instr_path;????MappingCallback?vm_snapshot_instr;??std::string?isolate_snapshot_data_path;????MappingCallback?isolate_snapshot_data;??std::string?isolate_snapshot_instr_path;????MappingCallback?isolate_snapshot_instr;??//?library?模式下的lib文件路徑??std::string?application_library_path;??//?icudlt.dat?文件路徑??std::string?icu_data_path;??//?flutter_assets?資源文件夾路徑??std::string?assets_path;??//?...}

    以加載vm_snapshot_data為例,它的加載邏輯如下:

    load vm_snapshot_data

    std::unique_ptr?ResolveVMData(const?Settings&?settings)?{??//?從?settings.vm_snapshot_data?中取??if?(settings.vm_snapshot_data)?{????...??}??//?從?settings.vm_snapshot_data_path?中取??if?(settings.vm_snapshot_data_path.size()?>?0)?{????...??}??//?從?settings.application_library_path?中取??if?(settings.application_library_path.size()?>?0)?{????...??}??auto?loaded_process?=?fml::NativeLibrary::CreateForCurrentProcess();??//?根據?kVMDataSymbol?從native?library中加載??return?DartSnapshotBuffer::CreateWithSymbolInLibrary(??????loaded_process,?DartSnapshot::kVMDataSymbol);}

    對于iOS來說,它默認會根據kVMDataSymbol來從App中加載對應資源,而其實settings是給提供了通過path的方式來加載資源和snapshot入口,那么對于 flutter_assets、icudtl.dat這些靜態資源,我們完全可以將其移出托管到服務端,然后動態下發。

    而由于iOS系統的限制,整個App可執行文件則不可以動態下發,但在第二部分的介紹中我們了解到,其實App是由kDartVmSnapshotData、kDartVmSnapshotInstructions、kDartIsolateSnapshotData、kDartIsolateSnapshotInstructions等四個部分組成的,其中kDartIsolateSnapshotInstructions、kDartVmSnapshotInstructions為指令段,不可通過動態下發的方式來加載,而kDartIsolateSnapshotData、kDartVmSnapshotData為數據段,它們在加載時不存在限制。

    到這里,其實我們就可以得到iOS側Flutter包大小的優化方案:將flutter_assets、icudtl.dat等靜態資源及kDartVmSnapshotData、kDartIsolateSnapshotData兩部分在編譯時拆分出去,通過動態下發的方式來實現包大小的縮減。但此方案有個問題,kDartVmSnapshotData、kDartIsolateSnapshotData是在編譯時就寫入到App中了,如何實現自動化地把此部分拆分出去是一個待解決的問題。為了解決此問題,我們需要先了解kDartVmSnapshotData、kDartIsolateSnapshotData的寫入時機。接下來,我們通過下圖6來簡單地介紹一下該過程:

    圖6 Flutter Data段寫入時序圖

    代碼通過gen_snapshot工具來進行編譯,它的入口在gen_snapshot.cc文件,通過初始化、預編譯等過程,最終調用Dart_CreateAppAOTSnapshotAsAssembly方法來寫入snapshot。因此,我們可以通過修改此流程,在寫入snapshot時只將instructions寫入,而將data重定向輸入到文件,即可實現 kDartVmSnapshotData、kDartIsolateSnapshotData與App的分離。此部分流程示意圖如下圖7所示:

    圖7 Flutter產物拆分流程示意圖

    3.1.2 工程化方案

    在完成了App數據段與代碼段分離的工作后,我們就可以將數據段及資源文件通過動態下發、運行時加載的方式來實現包體積的縮減。由此思路衍生的iOS側整體方案的架構如下圖8所示;其中定制編譯產物階段主要負責定制Flutter engine及Flutter SDK,以便完成產物的“瘦身”工作;發布集成階段則為產物的發布和工程集成提供了一套標準化、自動化的解決方案;而運行階段的使命是保證“瘦身”的資源在engine啟動的時候能被安全穩定地加載。

    圖8 架構設計

    注:圖例中MTFlutterRoute為Flutter路由容器,MWS指的是美團云。

    3.1.2.1 定制編譯產物階段

    雖然我們不能把App.framework及Flutter.framework通過動態下發的方式完全拆分出去,但可以剝離出部分非安裝時必須的產物資源,通過動態下發的方式來達到Flutter包體積縮減的目的,因此在該階段主要工作包括三部分。

    1. 新增編譯command

    在將Flutter包瘦身工程化時,我們必須保證現有的流程的編譯規則不會被影響,需要考慮以下兩點:

    • 增加編譯“瘦身”的Flutter產物構建模式, 該模式應能編譯出AOT模式下的瘦身產物。
    • 不對常規的編譯模式(debug、profile、release)引入影響。

    對于iOS平臺來說,AOT模式Flutter產物編譯的關鍵工作流程圖如下圖9所示。runCommand會將編譯所需參數及環境變量封裝傳遞給編譯后端(gen_snapshot負責此部分工作),進而完成產物的編譯工作:

    圖9 AOT模式Flutter產物編譯的關鍵工作流程圖

    為了實現“瘦身”的工作流,工具鏈在圖9的流程中新增了buildwithoutdata的編譯command,該命令針對通過傳遞相應參數(without-data=true)給到編譯后端(gen_snapshot),為后續編譯出剝離data段提供支撐:

    xcode_backend.sh

    if?[[?$#?==?0?]];?then??#?Backwards-compatibility:?if?no?args?are?provided,?build.??BuildAppelse??case?$1?in????"build")??????BuildApp?;;????"buildWithoutData")??????BuildAppWithoutData?;;????"thin")??????ThinAppFrameworks?;;????"embed")??????EmbedFlutterFrameworks?;;??esacfi

    build_aot.dart

    ..addFlag('without-data',????????negatable:?false,????????defaultsTo:?false,????????hide:?true,??)

    2. 編譯后端定制

    該部分主要對gen_snapshot工具進行定制,當gen_snapshot工具在接收到Dart層傳來的“瘦身”命令時,會解析參數并執行我們定制的方法Dart_CreateAppAOTSnapshotAsAssembly,該部分主要做了兩件事:

    • 定制產物編譯過程,生成剝離data段的編譯產物。
    • 重定向data段到文件中,以便后續進行使用。

    具體到處理的細節,首先我們需要在gen_sanpshot的入口處理傳參,并指定重定向data文件的地址:

    gen_snapshot.cc

    ??CreateAndWritePrecompiledSnapshot()?{????...????if?(snapshot_kind?==?kAppAOTAssembly)?{?//?常規release模式下產物的編譯流程??????...????}?else?if?(snapshot_kind?==?kAppAOTAssemblyDropData)?{???????...??????result?=?Dart_CreateAppAOTSnapshotAsAssembly(StreamingWriteCallback,????????????????????????????????????????????????????file,????????????????????????????????????????????????????&vm_snapshot_data_buffer,???????????????????????????????????????????????????&vm_snapshot_data_size,???????????????????????????????????????????????????&isolate_snapshot_data_buffer,???????????????????????????????????????????????????&isolate_snapshot_data_size,???????????????????????????????????????????????????true);?//?定制產物編譯過程,生成剝離data段的編譯產物snapshot_assembly.S??????...????}?else?if?(...)?{??????...????}????...??}

    在接受到編譯“瘦身”模式的命令后,將會調用定制的FullSnapshotWriter類來實現Snapshot_assembly.S的生成,該類會將原有編譯過程中vm_snapshot_data、isolate_snapshot_data的寫入過程改寫成緩存到buff中,以便后續寫入到獨立的文件中:

    dart_api_imp.cc

    //?drop_data=true,?表示后瘦身模式的編譯過程//?vm_snapshot_data_buffer、isolate_snapshot_data_buffer用于保存?vm_snapshot_data、isolate_snapshot_data以便后續寫入文件Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback?callback,????????????????????????????????????void*?callback_data,?????????????????????????????????????bool?drop_data,????????????????????????????????????uint8_t**?vm_snapshot_data_buffer,????????????????????????????????????uint8_t**?isolate_snapshot_data_buffer)?{??...??FullSnapshotWriter?writer(Snapshot::kFullAOT,?&vm_snapshot_data_buffer,????????????????????????????&isolate_snapshot_data_buffer,?ApiReallocate,????????????????????????????&image_writer,?&image_writer);??if?(drop_data)?{????writer.WriteFullSnapshotWithoutData();?//?分離出數據段??}?else?{????writer.WriteFullSnapshot();??}??...}

    當data段被緩存到buffer中后,便可以使用gen_snapshot提供的文件寫入的方法 WriteFile來實現數據段以文件形式從編譯產物中分離:

    gen_snapshot.cc

    static?void?WriteFile(const?char*?filename,?const?uint8_t*?buffer,?const?intptr_t?size);//?寫data到指定文件中{??...??????WriteFile(vm_snapshot_data_filename,?vm_snapshot_data_buffer,?vm_snapshot_data_size);?//?寫入vm_snapshot_data??????WriteFile(isolate_snapshot_data_filename,?isolate_snapshot_data_buffer,?isolate_snapshot_data_size);?//?寫入isolate_snapshot_data??...}

    3. engine定制

    編譯參數修改

    iOS側使用-0z參數可以獲得包體積縮減的收益(大約為700KB左右的收益),但會有相應的性能損耗,因此該部分作為一個可選項提供給業務方,工具鏈提供相應版本的Flutter engine的定制。

    資源加載方式定制

    對于engine的定制,主要圍繞如何“手動”引入拆分出的資源來展開,好在engine提供了settings接口讓我們可以實現自定義引入文件的path,因此我們需要做的就是對Flutter engine初始化的過程進行相應改造:

    shell/platform/darwin/ios/framework/Headers/FlutterDartProject.h

    /**?*?custom?icudtl.dat?path?*/@property(nonatomic,?copy)?NSString*?icuDataPath;/**?*?custom?flutter_assets?path?*/@property(nonatomic,?copy)?NSString*?assetPath;/**?*?custom?isolate_snapshot_data?path?*/@property(nonatomic,?copy)?NSString*?isolateSnapshotDataPath;/**?*custom?vm_snapshot_data?path?*/@property(nonatomic,?copy)?NSString*?vmSnapshotDataPath;

    在運行時“手動”配置上述路徑,并結合上述參數初始化FlutterDartProject,從而達到engine啟動時從配置路徑加載相應資源的目的。

    engine編譯自動化

    在完成engine的定制和改造后,還需要手動編譯一下engine源碼,生成各平臺、架構、模式下的產物,并將其集成到Flutter SDK中,為了讓引擎定制的流程標準化、自動化,MTFlutter工具鏈提供了一套engine自動化編譯發布的工具。如流程圖10所示,在完成engine代碼的自定義修改之后,工具鏈會根據engine的patch code編譯出各平臺、架構及不同模式下的engine產物,然后自動上傳到美團云上,在開發和打包時只需要通簡單的命令,即可安裝和使用定制后的Flutter engine:

    圖10 Flutter engine自動化編譯發布流程

    3.1.2.2 發布集成階段

    當完成Dart代碼編譯產物的定制后,我們下一步要做的就是改造MTFlutter工具鏈現有的產物發布流程,支持打出“瘦身”模式的產物,并將瘦身模式下的產物進行合理的組織、封裝、托管以方便產物的集成。從工具鏈的視角來看,該部分的流程示如下圖11所示:

    圖11 Flutter產物發布集成流程示意圖

    自動化發布與版本管理

    MTFlutter工具鏈將“瘦身”集成到產物發布的流水線中,新增一種thin模式下的產物,在iOS側該產物包括release模式下瘦身后的App.framework、Flutter.framework以及拆分出的數據、資源等文件。當開發者提交了代碼并使用Talos(美團內部前端持續交付平臺)觸發Flutter打包時,CI工具會自動打出瘦身的產物包及需要運行時下載的資源包、生成產物相關信息的校驗文件并自動上傳到美團云上。

    對于產物資源的版本管理,我們則復用了美團云提供資源管理的能力。在美團云上,產物資源以文件目錄的形式來實現各版本資源的相互隔離,同時對“瘦身”資源單獨開一個bucket進行單獨管理,在集成產物時,集成插件只需根據當前產物module的名稱及版本號便可獲取對應的產物。

    自動化集成

    針對瘦身模式MTFlutter工具鏈對集成插件也進行了相應的改造,如下圖12所示。我們對Flutter集成插件進行了修改,在原有的產物集成模式的基礎上新增一種thin模式,該模式在表現形式與原有的debug、release、profile類似,區別在于:為了方便開發人員調試,該模式會依據當前工程的buildconfigration來做相應的處理,即在debug模式下集成原有的debug產物,而在release模式下才集成“瘦身”產物包。

    圖12 Flutter iOS端集成插件修改

    3.1.2.3 運行階段

    運行階段所處理的核心問題包括資源下載、緩存、解壓、加載及異常監控等。一個典型的瘦身模式下的engine啟動的過程如圖13所示。

    該過程包括:

    • 資源下載:讀取工程配置文件,得到當前Flutter module的版本,并查詢和下載遠程資源。
    • 資源解壓和校驗:對下載資源進行完整性校驗,校驗完成則進行解壓和本地緩存。
    • 啟動engine:在engine啟動時加載下載的資源。
    • 監控和異常處理:對整個流程可能出現的異常情況進行處理,相關數據情況進行監控上報。

    圖13 iOS側瘦身模式下engine啟動流程圖

    為了方便業務方的使用、減少其接入成本,MTFlutter將該部分工作集成至MTFlutterRoute中,業務方僅需引入MTFlutterRoute即可將“瘦身”功能接入到項目中。

    3.2 Android側方案

    3.2.1 整體架構

    在Android側,我們做到了除Java代碼外的所有Flutter產物都動態下發。完整的優化方案概括來說就是:動態下發+自定義引擎初始化+自定義資源加載。方案整體分為打包階段和運行階段,打包階段會將Flutter產物移除并生成瘦身的APK,運行階段則完成產物下載、自定義引擎初始化及資源加載。其中產物的上傳和下載由DynLoader完成,這是由美團平臺迭代工程組提供的一套so與assets的動態下發框架,它包括編譯時和運行時兩部分的操作:

  • 工程配置:配置需要上傳的so和assets文件。
  • App打包時,會將配置1中的文件壓縮上傳到動態發布系統,并從APK中移除。
  • App每次啟動時,向動態發布系統發起請求,請求需要下載的壓縮包,然后下載到本地并解壓,如果本地已經存在了,則不進行下載。
  • 我們在DynLoader的基礎上,通過對Flutter引擎初始化及資源加載流程進行定制,設計了整體的Flutter包大小優化方案:

    圖14 Android側Flutter包大小優化方案整體架構

    打包階段:我們在原有的APK打包流程中,加入一些自定義的gradle plugin來對Flutter產物進行處理。在預處理流程,我們將一些無用的資源文件移除,然后將flutter_assets中的文件打包為bundle.zip。然后通過DynLoader提供的上傳插件將libflutter.so、libapp.so和flutter_assets/bundle.zip從APK中移除,并上傳到動態發布系統托管。其中對于多架構的so,我們通過在build.gradle中增加abiFilters進行過濾,只保留單架構的so。最終打包出來的APK即為瘦身后的APK。

    不經處理的話,瘦身后的APK一進到Flutter頁面肯定會報錯,因為此時so和flutter_assets可能都還沒下載下來,即使已經下載下來,其位置也發生了改變,再使用原來的加載方式肯定會找不到。所以我們在運行階段需要做一些特殊處理:

    1. Flutter路由攔截

    首先要使用Flutter路由攔截器,在進到Flutter頁面之前,要確保so和flutter_assets都已經下載完成,如果沒有下載完,則顯示loading彈窗,然后調用DynLoader的方法去異步下載。當下載完成后,再執行原來的跳轉邏輯。

    2. 自定義引擎初始化

    第一次進到Flutter頁面,需要先初始化Flutter引擎,其中主要是將libflutter.so和libapp.so的路徑改為動態下發的路徑。另外還需要將flutter_assets/bundle.zip進行解壓。

    3. 自定義資源加載

    當引擎初始化完成后,開始執行Dart代碼的邏輯。此時肯定會遇到資源加載,比如字體或者圖片。原有的資源加載器是通過method channel調用AssetManager的方法,從APK中的assets中進行加載,我們需要改成從動態下發的路徑中加載。

    下面我們詳細介紹下某些部分的具體實現。

    3.2.2 自定義引擎初始化

    原有的Flutter引擎初始化由FlutterMain類的兩個方法完成,分別為startInitialization和ensureInitializationComplete,一般在Application初始化時調用startInitialization(懶加載模式會延遲到啟動Flutter頁面時再調用),然后在Flutter頁面啟動時調用ensureInitializationComplete確保初始化的完成。

    圖15 Android側Flutter引擎初始化流程圖

    在startInitialization方法中,會加載libflutter.so,在ensureInitializationComplete中會構建shellArgs參數,然后將shellArgs傳給FlutterJNI.nativeInit方法,由jni側完成引擎的初始化。其中shellArgs中有個參數AOT_SHARED_LIBRARY_NAME可以用來指定libapp.so的路徑。

    自定義引擎初始化,主要要修改兩個地方,一個是System.loadLibrary("flutter"),一個是shellArgs中libapp.so的路徑。有兩種辦法可以做到:

    • 直接修改FlutterMain的源碼,這種方式簡單直接,但是需要修改引擎并重新打包,業務方也需要使用定制的引擎才可以。
    • 繼承FlutterMain類,重寫startInitialization和ensureInitializationComplete的邏輯,讓業務方使用我們的自定義類來初始化引擎。當自定義類完成引擎的初始化后,通過反射的方式修改sSettings和sInitialized,從而使得原有的初始化邏輯不再執行。

    本文使用第二種方式,需要在FlutterActivity的onCreate方法中首先調用自定義的引擎初始化方法,然后再調用super的onCreate方法。

    3.2.3 自定義資源加載

    Flutter中的資源加載由一組類完成,根據數據源的不同分為了網絡資源加載和本地資源加載,其類圖如下:

    圖16 Flutter 資源加載相關類圖

    AssetBundle為資源加載的抽象類,網絡資源由NetworkAssetBundle加載,打包到Apk中的資源由PlatformAssetBundle加載。

    PlatformAssetBundle通過channel調用,最終由AssetManager去完成資源的加載并返回給Dart層。

    我們無法修改PlatformAssetBundle原有的資源加載邏輯,但是我們可以自定義一個資源加載器對其進行替換:在widget樹的頂層通過DefaultAssetBundle注入。

    自定義的資源加載器DynamicPlatformAssetBundle,通過channel調用,最終從動態下發的flutter_assets中加載資源。

    3.2.4 字體動態加載

    字體屬于一種特殊的資源,其有兩種加載方式:

    • 靜態加載:在pubspec.yaml文件中聲明的字體及為靜態加載,當引擎初始化的時候,會自動從AssetManager中加載靜態注冊的字體資源。
    • 動態加載:Flutter提供了FontLoader類來完成字體的動態加載。

    當資源動態下發后,assets中已經沒有字體文件了,所以靜態加載會失敗,我們需要改為動態加載。

    3.2.5 運行時代碼組織結構

    整個方案的運行時部分涉及多個功能模塊,包括產物下載、引擎初始化、資源加載和字體加載,既有Native側的邏輯,也有Dart側的邏輯。如何將這些模塊合理的加以整合呢?平臺團隊的同學給了很好的答案,并將其實現為一個Flutter Plugin:flutter_dynamic(美團內部庫)。其整體分為Dart側和Android側兩部分,Dart側提供字體和資源加載方法,方法內部通過method channel調到Android側,在Android側基于DynLoader提供的接口實現產物下載和資源加載的邏輯。

    圖17 FlutterDynamic結構圖

    四、方案的接入與使用

    為了讓大家了解上述方案使用層面的設計,我們在此把美團內部的使用方式介紹給大家,其中會涉及到一些內部工具細節我們暫不展開,重點解釋設計和使用體驗部分。由于Android和iOS的實現方案有所區別,故在接入方式相應的也會有些差異,下面針對不同平臺分開進行介紹:

    4.1 iOS

    在上文方案的設計中,我們介紹到包瘦身功能已經集成進入美團內部MTFlutter工具鏈中,因此當業務方在使用了MTFlutter后只需簡單的幾步配置便可實現包瘦身功能的接入。iOS 的接入使用上總體分為三步:

    1. 引入Flutter集成插件(cocoapods-flutter-plugin 美團內部Cocoapods插件,進一步封裝Flutter模塊引入,使之更加清晰便捷):

    Gemfile

    gem?'cocoapods-flutter-plugin',?'~>?1.2.0'

    2. 接入MTFlutterRoute混合業務容器(美團內部pod庫,封裝了Flutter初始化及全局路由等能力),實現基于“瘦身”產物的初始化:

    Flutter 業務工程中引入 mt_flutter_route:

    pubspec.yaml

    dependencies:??mt_flutter_route:?^2.4.0

    3. 在iOS Native工程中引入MTFlutterRoute pod:

    podfile

    binary_pod?'MTFlutterRoute',?'2.4.1.8'

    經過上面的配置后,正常Flutter業務發版時就會自動產生“瘦身”后的產物,此時只需在工程中配置瘦身模式即可完成接入:

    podfile

    flutter?'your_flutter_project',?'x.x.x',?:thin?=>?true

    4.2 Android

    4.2.1 Flutter側修改

    1. 在Flutter工程pubspec.yaml中添加flutter_dynamic(美團內部Flutter Plugin,負責Dart側的字體、資源加載)依賴。

    2. 在main.dart中添加字體動態加載邏輯,并替換默認資源加載器。

    main.dart

    void?main()?async?{???//?動態加載字體??await?dynFontInit();??//?自定義資源加載器??runApp(DefaultAssetBundle(????bundle:?dynRootBundle,????child:?MyApp(),??));}

    4.2.2 Native 側修改

    1. 打包腳本修改

    在App模塊的build.gradle中通過apply特定plugin完成產物的刪減、壓縮以及上傳。

    2. 在Application的onCreate方法中初始化FlutterDynamic。

    3. 添加Flutter頁面跳轉攔截。

    在跳轉到Flutter頁面之前,需要使用FlutterDynamic提供的接口來確保產物已經下載完成,在下載成功的回調中來執行真正的跳轉邏輯。

    class?FlutterRouteUtil?{????public?static?void?startFlutterActivity(final?Context?context,?Intent?intent)?{????????FlutterDynamic.getInstance().ensureLoaded(context,?new?LoadCallback()?{????????????@Override????????????public?void?onSuccess()?{??????????????//?在下載成功的回調中執行跳轉邏輯????????????????context.startActivity(intent);????????????}????????});????}}

    備注:如果App有使用類似WMRoute之類的路由組件的話,可以自定義一個UriHandler來統一處理所有的Flutter頁面跳轉,同樣在ensureLoaded方法回調中執行真正的跳轉邏輯。

    4. 添加引擎初始化邏輯

    我們需要重寫FlutterActivity的onCreate方法,在super.onCreate之前先執行自定義的引擎初始化邏輯。

    MainFlutterActivity.java

    public?class?MainFlutterActivity?extends?FlutterActivity?{????@Override????protected?void?onCreate(Bundle?savedInstanceState)???????//?確保自定義引擎初始化完成????????FlutterDynamic.getInstance().ensureFlutterInit(this);????????super.onCreate(savedInstanceState);????}}

    五、總結展望

    目前,動態下發的方案已在美團內部App上線使用,Android包瘦身效果到達95%,iOS包瘦身效果達到30%+。動態下發的方案雖然能顯著減少Flutter的包體積,但其收益是通過運行時下載的方式置換回來的。當Flutter業務的不斷迭代增長時,Flutter產物包也會隨之不斷變大,最終導致需下載的產物變大,也會對下載成功率帶來壓力。

    未來,我們還會探索Flutter的分包邏輯,通過將不同的業務模塊拆分來降低單個產物包的大小,來進一步保障包瘦身功能的可用性。

    六、作者簡介

    艷東,2018年加入美團,到家平臺前端工程師。

    宗文,2019年加入美團,到家平臺前端高級工程師。

    會超,2014年加入美團,到家平臺前端技術專家。

    ---------- END ----------

    招聘信息

    美團外賣長期招聘Android、iOS、FE 高級/資深工程師和技術專家。歡迎感興趣的同學投遞簡歷至:tech@meituan.com(郵件標題請注明:美團外賣技術團隊)。

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的android nio debug模式正常 release包crash_Flutter包大小治理上的探索与实践的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    a视频在线播放 | av大片免费在线观看 | 日日麻批40分钟视频免费观看 | 五月亚洲 | 久久在线观看视频 | 91视频在线自拍 | 中文av网| 五月婷婷综合久久 | 三级午夜片 | 一区中文字幕在线观看 | 久久久91精品国产一区二区三区 | 九九在线精品视频 | 欧美一二区在线 | 91视频免费国产 | 狠狠操影视 | 天天干天天做 | 国产精品久久久久久欧美 | 亚洲天天在线日亚洲洲精 | 激情电影在线观看 | 999ZYZ玖玖资源站永久 | 在线观看视频在线 | 综合久久网站 | 玖操 | 精品久操 | 精品久久久久久久久亚洲 | 免费黄色看片 | 国产精品麻豆果冻传媒在线播放 | 国模一二三区 | 看全黄大色黄大片 | 日p视频 | 色吊丝在线永久观看最新版本 | 精品欧美一区二区精品久久 | 美女国产在线 | 国产综合小视频 | 人人超碰在线 | av在线免费在线观看 | 欧美激情在线网站 | 国产精品日韩在线播放 | 99久久日韩精品视频免费在线观看 | 日韩特黄一级欧美毛片特黄 | 一区二区伦理 | 久久久精品99 | 婷婷五天天在线视频 | 人人澡人人舔 | 麻豆一二 | 亚洲美女在线国产 | 久久精品亚洲一区二区三区观看模式 | 欧美日韩国产色综合一二三四 | 激情丁香综合五月 | 久久综合久久综合久久综合 | 日韩一二区在线观看 | 国产精品久久久久影视 | 色99导航| 日韩免费视频在线观看 | 嫩草av影院 | 国产中文字幕一区二区三区 | 亚洲日本中文字幕在线观看 | 亚洲精品乱码久久久久久久久久 | 久草精品视频在线看网站免费 | 国产精品成人一区二区三区吃奶 | 久久婷婷开心 | 99久久精品国产一区二区三区 | 五月婷香蕉久色在线看 | 91九色pron| 波多野结衣视频一区二区三区 | 国产一级一片免费播放放 | 最新av在线播放 | 久久精品国产一区二区 | 国语对白少妇爽91 | 91色网址| 天天插天天射 | 在线观看中文字幕第一页 | 欧美 日韩 性 | 国产一二区免费视频 | 国产一区麻豆 | a久久免费视频 | 免费色网 | 国产黄a三级三级 | 99免费在线视频观看 | 亚洲天堂网在线观看视频 | 国产一区在线免费观看视频 | 亚洲五月综合 | 99在线热播精品免费99热 | 亚洲国产一区二区精品专区 | 五月天久久 | 不卡的av电影在线观看 | 操操操人人 | 97色综合 | 亚洲永久精品在线观看 | 久久99亚洲精品久久久久 | 免费在线观看av网站 | 美女视频黄频大全免费 | 97超级碰碰碰视频在线观看 | 中文字幕在线视频精品 | 精品麻豆| 天天干国产 | 97在线观看免费观看高清 | 天天干天天操天天干 | 久草精品视频在线播放 | 国产精品久久麻豆 | 麻豆影视在线播放 | 五月天综合在线 | 偷拍福利视频一区二区三区 | 韩日电影在线观看 | 久久99深爱久久99精品 | 超碰在线cao | 亚洲精品tv久久久久久久久久 | 正在播放一区 | 国产亚洲视频中文字幕视频 | 国产精品免费麻豆入口 | 亚洲日本激情 | 久久伊人综合 | 麻豆传媒精品 | 国产99久久久国产精品免费二区 | 国产原创在线视频 | 精品久久久久久综合日本 | 婷婷色社区 | 久久成人一区 | 99麻豆久久久国产精品免费 | 91.精品高清在线观看 | 久久99热精品这里久久精品 | 99免费在线观看 | 久久夜色精品国产欧美乱极品 | 亚洲国产中文在线 | 98涩涩国产露脸精品国产网 | 亚洲一级理论片 | 欧美国产在线看 | 欧美日韩视频在线播放 | 成人一级在线 | 国产在线精品国自产拍影院 | 国产91av视频在线观看 | 日日夜夜噜 | 国产日韩亚洲 | 综合久久久久久 | 在线观看视频中文字幕 | 一级黄色a视频 | 精久久久久 | 亚洲精品一区二区三区新线路 | 日韩精品一区二区在线视频 | av视屏在线 | 在线国产中文字幕 | 五月综合激情 | 婷婷成人在线 | 国产原创在线 | 在线免费黄色av | 97电影在线观看 | 精品视频一区在线观看 | 中文字幕一区二区三区久久 | 精品1区2区 | 日韩啪啪小视频 | 欧美另类v | 成人午夜黄色影院 | 精品成人国产 | 免费成人在线电影 | 99久久99精品 | 天天色天| 久久99九九99精品 | av888.com| 亚洲精品h | 免费成人av在线 | 麻豆91小视频 | 国产精品欧美在线 | 中文成人字幕 | 国产一二区视频 | 欧美黑吊大战白妞欧美 | 韩日电影在线 | 国产精品久久久网站 | 国产精品免费视频久久久 | 欧美日韩高清在线 | 久久久久久久久久久久99 | 国产美女视频 | 91热视频在线观看 | 国产精品久久久久久久婷婷 | 天天操天天射天天爱 | 久草av在线播放 | 亚洲成av人片 | 午夜精品久久久久久久99 | 在线香蕉视频 | 欧美另类v | 欧美日韩高清一区二区 | 日韩视频一区二区 | 久久91网| 天天爽夜夜爽人人爽一区二区 | 国产精品久久久亚洲 | 激情综合交 | 国产精品福利小视频 | 久久久久久久久久久久影院 | 国内精品久久久久久久影视简单 | 久久夜色电影 | 久久久精品国产免费观看一区二区 | 日韩在线小视频 | 最近乱久中文字幕 | 天天操天天添 | 国产午夜在线 | 欧美一区二区三区在线观看 | 国产1级视频 | 国产1区2区 | 国产精品999久久久 久产久精国产品 | 中文字幕在线观看视频一区 | 香蕉影院在线播放 | 国产在线一区观看 | av免费在线免费观看 | 国产精品丝袜 | 96精品视频 | 四虎成人精品永久免费av | 91经典在线 | 毛片网站免费在线观看 | 欧美日韩国产一区二区在线观看 | 99热这里精品 | 欧美性生活免费 | 亚洲h在线播放在线观看h | 97在线看片| 日本中文字幕在线看 | 在线观看亚洲国产 | av成人黄色 | 国产91精品一区二区麻豆网站 | 国产精品久久久一区二区三区网站 | 国产玖玖视频 | 亚洲专区视频在线观看 | 成人日批视频 | 日韩精品一区二区在线视频 | 亚洲男女精品 | 97视频在线观看成人 | 欧美日本一区 | 丁香影院在线 | 狠狠88综合久久久久综合网 | www色综合| 韩国av一区二区三区在线观看 | 黄av在线| 亚洲欧美日韩在线一区二区 | 久久免费av电影 | 精品久久久久久久久中文字幕 | aaa黄色毛片| 国产一线二线三线性视频 | 午夜色场| 国产精品久久久久亚洲影视 | 国产精品久久久久aaaa | www.com久久| 国产精品黄色在线观看 | 久久中文精品视频 | 亚洲一二三久久 | 一级黄色免费网站 | 精品在线观看一区二区 | 国产高清免费观看 | 精品国产乱码久久久久久1区2匹 | 成人免费视频a | 91人人澡人人爽人人精品 | 91精品国产一区二区三区 | 亚洲全部视频 | 毛片网在线播放 | 高潮久久久久久 | 午夜精品久久久99热福利 | 成人在线播放免费观看 | 手机看片国产日韩 | 日韩黄色中文字幕 | 激情在线五月天 | 精品国产乱码久久久久久三级人 | 一级黄色片毛片 | 少妇资源站 | 日韩一区二区三区不卡 | 西西www4444大胆视频 | 一级淫片在线观看 | 国产欧美高清 | 久草在线手机视频 | 精品三级av | 五月天九九 | 91完整版在线观看 | 欧美日bb| 午夜国产一区二区三区四区 | 免费高清在线观看成人 | 97理论片 | 亚欧日韩av | www成人av| 91看片在线看片 | av电影免费在线 | 久久99久久99免费视频 | 久久久精品高清 | 中文字幕免费高清 | 99久热精品| 在线播放视频一区 | 中文字幕国产精品 | 91福利在线观看 | 99热在 | 日本精品视频在线播放 | 国产又黄又猛又粗 | 欧美性生活免费 | 久久久久国产精品www | 99热在线免费观看 | 日韩区欧美久久久无人区 | 一区二区三区动漫 | 五月激情综合婷婷 | 91丨九色丨蝌蚪丰满 | 黄色软件在线观看免费 | 久久久穴| av网址aaa| 欧美另类一二三四区 | 日韩精品一区二区在线观看视频 | 成人禁用看黄a在线 | 在线小视频 | 久久成人一区 | 久久精品99久久久久久 | 一级黄色a视频 | 丁香激情综合久久伊人久久 | 久久成人18免费网站 | 91香蕉亚洲精品 | 成人黄色短片 | 久久精品—区二区三区 | 婷婷五月情 | 亚洲在线网址 | 久久精品二区 | 黄色成人av网址 | 欧美日韩国产一区二区三区 | 国产精品麻豆免费版 | 五月天婷亚洲天综合网精品偷 | 国产一区二区三精品久久久无广告 | 91精品视频在线看 | 三日本三级少妇三级99 | 香蕉视频免费看 | 久热av| 国产aaa免费视频 | 精品在线一区二区 | 日韩免费看视频 | 能在线观看的日韩av | 欧美美女激情18p | 成人三级视频 | 五月视频 | 337p西西人体大胆瓣开下部 | 三级午夜片 | 日韩欧美在线观看一区二区 | 在线免费观看av网站 | 日韩精品一区二区三区不卡 | 四虎免费在线观看 | 九九热国产| 久久久综合九色合综国产精品 | 色婷婷狠狠18 | 国产中文| 国产亚洲激情视频在线 | 亚洲黄色免费 | 黄视频网站大全 | 精品久久久99 | 在线免费视频a | 国产黄色大片 | 97超碰人人 | 美女视频免费精品 | 日日夜夜添 | 国产精品一区二 | 久久这里 | 国产精品区二区三区日本 | 狠狠久久婷婷 | 亚洲天堂激情 | 天天干天天做天天操 | 新版资源中文在线观看 | 99久久激情视频 | 丁香六月天 | 麻豆系列在线观看 | 天天操天天色天天射 | 午夜国产在线 | 久久精品第一页 | 国内精品在线观看视频 | 久久精品一二区 | 欧美在线视频精品 | 西西人体4444www高清视频 | 九九免费在线看完整版 | 日韩成人免费在线电影 | av一区二区三区在线 | 丁香久久婷婷 | 国产日韩欧美精品在线观看 | 色综合婷婷久久 | 国产精品9999久久久久仙踪林 | 亚洲女人天堂成人av在线 | 91av在线免费视频 | 综合网成人| 在线一区二区三区 | 久久精品国产一区二区三区 | 日韩在线观看小视频 | 日韩欧美国产激情在线播放 | 久久久久久久久亚洲精品 | 国产小视频在线播放 | 三级av免费 | 天天操天天干天天玩 | 天天天天天天天天操 | 国产精品久久久999 国产91九色视频 | 丰满少妇在线观看 | 91在线中字 | 亚洲欧美成人综合 | 亚洲国产免费网站 | 天天草天天插 | 久草免费手机视频 | 丁香六月婷婷激情 | 久久久国产网站 | 久久精品91久久久久久再现 | 欧美精品国产精品 | 亚洲区视频在线 | 狠狠久久综合 | 在线观看视频免费播放 | 中文字幕在线有码 | 婷婷av色综合 | 国产日产精品一区二区三区四区的观看方式 | 精品一区二区三区四区在线 | av看片在线观看 | 国产91精品高清一区二区三区 | 日本在线中文 | 亚洲精品久久久蜜桃直播 | 午夜视频久久久 | 久久99精品国产 | 99色在线观看视频 | 免费成人在线观看视频 | 91精品视频免费观看 | 日日夜夜天天久久 | 美女视频黄在线 | 丁香花中文在线免费观看 | 亚洲少妇xxxx | 亚洲成人av片在线观看 | 国产一区二区三区网站 | 免费人成在线观看网站 | 黄色免费av | 天天综合精品 | jizz欧美性9 国产一区高清在线观看 | 九九热国产视频 | 久久久国产电影 | www.色午夜 | 激情五月婷婷综合 | 久久久久成人精品免费播放动漫 | 国产91丝袜在线播放动漫 | 国产精品99久久久久久大便 | 亚洲激情在线 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产精品美女久久久久久 | 亚洲欧美视频网站 | 欧美成人中文字幕 | 国产精品久久久影视 | av在线8 | 欧美欧美| 日韩精品一区二区三区三炮视频 | av成人免费在线观看 | 草久久精品 | 国产麻豆剧果冻传媒视频播放量 | 成人久久18免费网站麻豆 | 日本99精品 | 日韩免费看片 | 欧美日韩国产精品一区二区 | 中文字幕资源在线观看 | 亚洲国产精品视频在线观看 | 狠狠色婷婷丁香六月 | 欧美日韩高清在线 | 精品亚洲欧美无人区乱码 | 91激情视频在线观看 | 日韩黄视频| 99色99| 中文字幕免费久久 | 精品福利视频在线观看 | 久久再线视频 | 日本久久中文字幕 | 九九在线视频 | 亚洲精品小视频 | 337p日本欧洲亚洲大胆裸体艺术 | 成人a毛片 | 国产日产精品一区二区三区四区的观看方式 | 国产大陆亚洲精品国产 | 亚a在线| 亚洲另类视频 | 黄色a视频免费 | 综合色综合色 | 国产精品日韩高清 | 中文字幕精品一区二区精品 | 久久看毛片 | 精品专区一区二区 | 天天操天天操天天操天天操天天操天天操 | 日本公妇在线观看 | 久久久久久不卡 | 人人舔人人 | 午夜国产福利视频 | 亚洲欧洲一区二区在线观看 | 欧美亚洲免费在线一区 | 国产福利专区 | 亚洲经典精品 | 97视频在线观看免费 | 精品久久免费看 | 中文字幕成人在线 | 久久人人爽人人爽人人片av软件 | 美女视频黄,久久 | 亚洲视频一区二区三区在线观看 | 在线观看精品黄av片免费 | 国产亚洲精品美女久久 | 久久精国产 | 国产精品免费不卡 | 日日夜夜免费精品视频 | 91视频高清 | 夜夜躁日日躁狠狠躁 | 成人免费视频网站在线观看 | 91黄视频在线观看 | 成 人 黄 色 片 在线播放 | 色资源中文字幕 | 久久dvd| 久久久久国产成人免费精品免费 | 亚洲黄色激情小说 | a色网站 | 中文字幕在线观看视频免费 | 九九导航 | 成人免费av电影 | 国产亚洲情侣一区二区无 | 午夜精品av | av先锋中文字幕 | 免费国产在线视频 | 在线日韩亚洲 | 激情网在线观看 | av免费网| www天天干com| 欧美日韩国产一区 | 午夜av免费看 | 91九色视频 | 99精品国产99久久久久久福利 | 婷婷色中文 | 久久九九精品久久 | 波多野结衣一区二区三区中文字幕 | 91毛片在线观看 | 成人免费在线播放视频 | 夜夜天天干 | 综合亚洲视频 | 精品视频中文字幕 | 五月婷婷激情 | 麻豆视频在线观看免费 | 911久久 | 免费日韩一区二区 | 国产亚洲精品成人av久久ww | 久久不卡免费视频 | 丁香五月亚洲综合在线 | 国产精品嫩草影视久久久 | 97久久精品午夜一区二区 | 国产精品欧美日韩在线观看 | 久久精品波多野结衣 | 国产在线久草 | 国产一区二区三区免费观看视频 | 精品国产一区二区三区在线 | 超碰人人草人人 | 99精品视频网 | 麻豆视频免费网站 | a级国产毛片 | 日本高清久久久 | 日本三级吹潮在线 | 久久久久北条麻妃免费看 | 日韩视频a | 国产成人一区二区三区影院在线 | 日日碰狠狠添天天爽超碰97久久 | 天天草综合| 欧美国产日韩中文 | 又爽又黄又刺激的视频 | 成人av中文字幕 | 伊人天堂av | 久久一区91 | 日本不卡一区二区三区在线观看 | 日日夜夜免费精品视频 | 成人免费xyz网站 | 国产一级电影在线 | 91精品国产91热久久久做人人 | 久久久久久久久久久电影 | 美女网站在线观看 | 福利一区二区 | 国产剧情一区二区在线观看 | 五月婷婷色播 | 国产中文字幕视频 | 色com网| 四虎4hu永久免费 | 亚洲人精品午夜 | 视频91 | 69亚洲精品| 亚洲视频免费 | 日韩在线第一 | 中文字幕av一区二区三区四区 | 插婷婷| 亚洲最新精品 | 婷婷午夜激情 | 91精品国产99久久久久 | 成人免费视频网 | 亚洲国产三级在线 | 久久视频精品 | 亚洲欧美国产精品va在线观看 | 精品日韩在线 | 最近日本中文字幕a | 亚洲少妇影院 | 97av在线视频免费播放 | 亚洲成人av一区 | 国内精品毛片 | 日韩性xxxx | 中文字幕 国产专区 | 91中文字幕视频 | 国产免费黄色 | 东方av在| 亚洲人久久久 | 久久久久久国产精品美女 | 91视频在线国产 | 成片视频免费观看 | 视频在线国产 | 国产一线二线三线性视频 | 欧美精品一二 | 亚洲免费在线观看视频 | 国产成人精品免高潮在线观看 | 超碰在线网| 一级免费黄色 | 成人免费视频播放 | 久久久久久国产精品美女 | 一区二区三区免费 | 热热热热热色 | 中文字幕在线观看的网站 | 久久久精选 | 午夜久久久久久久久久久 | 在线视频 区 | 夜夜爱av | 欧美精品xxx| 欧美日韩在线视频一区 | 国产精品资源在线 | 日韩欧美69 | 久久草精品 | 91亚洲视频在线观看 | 伊人宗合网| 久久视频国产 | 国产精品国产三级国产aⅴ入口 | www.久久久| 成年人天堂com | 国产精品久久久久久婷婷天堂 | 亚洲国产日韩一区 | 精品在线视频观看 | 国产精品99久久久久久武松影视 | 中文在线www | 国产精品高潮呻吟久久久久 | 日本丶国产丶欧美色综合 | 久久久国产精品网站 | 国模视频一区二区三区 | 国产999精品视频 | 永久av免费在线观看 | 伊人导航 | 久久国产日韩 | 欧美一级电影免费观看 | 亚洲视屏 | 九九免费在线观看 | 国产黄网在线 | 国产精品久久久久久影院 | 日韩一区二区在线免费观看 | 91大神精品视频在线观看 | 亚洲视频综合在线 | 啪啪肉肉污av国网站 | 国产不卡在线视频 | 人人插人人艹 | 国产在线播放观看 | 欧美日韩在线观看不卡 | 国产精品毛片一区视频播不卡 | 日韩av手机在线看 | 最近中文字幕大全 | 日本99热 | 日韩在线视频线视频免费网站 | 99国产精品一区 | 中文字幕亚洲五码 | 亚洲精品在线二区 | 狠狠色综合网站久久久久久久 | 激情影音先锋 | 超碰人人舔 | 日韩一二三区不卡 | 人人爽人人澡人人添人人人人 | 果冻av在线 | 成人av影视在线 | 在线观看的黄色 | 视频二区在线 | 香蕉免费在线 | 免费网站在线观看成人 | 免费看的黄网站 | 日本xxxxav| 丁香激情综合国产 | 婷婷在线视频 | 男女激情片在线观看 | 日韩在线免费不卡 | 亚州黄色一级 | 国产高清无线码2021 | 西西44人体做爰大胆视频 | 青青河边草免费直播 | 精品在线不卡 | 国产999精品久久久 免费a网站 | 久久久亚洲成人 | 日韩a欧美 | 五月开心激情网 | 国内精品小视频 | 免费看的黄色小视频 | 97超碰在线久草超碰在线观看 | 免费网址你懂的 | 日日夜夜干 | 国产精品18久久久久久久久久久久 | 亚洲五月婷婷 | 亚洲视屏在线播放 | 亚洲一区精品二人人爽久久 | 国产综合激情 | 五月婷婷在线视频 | 深夜免费福利网站 | 精品免费在线视频 | 免费观看一区二区三区视频 | 久久99国产精品二区护士 | 毛片一区二区 | 91麻豆精品国产 | 一区二区 久久 | 精品一区二区电影 | 青青河边草手机免费 | 国产精品久久久777 成人手机在线视频 | 毛片久久久 | 911久久| 欧美一级特黄高清视频 | 992tv在线成人免费观看 | www.香蕉视频在线观看 | 国产一区二区三区免费视频 | 激情网婷婷| 91在线播放视频 | 香蕉视频日本 | 人人看97 | 成人午夜电影在线 | 国产精品九九热 | 奇米网444| 精品免费国产一区二区三区四区 | 国产亚洲精品久久久久动 | 日韩欧美综合视频 | 人人躁 | 亚欧洲精品视频在线观看 | 丁香婷婷激情网 | 日韩欧美一区视频 | 在线 国产一区 | 97超碰人 | 午夜电影久久 | 波多野结衣在线观看视频 | 免费91在线| 69av久久 | 国产99色 | 国产精品一区二区吃奶在线观看 | 十八岁免进欧美 | a色网站| 91精品免费视频 | 久久狠狠婷婷 | 亚洲九九爱 | 在线精品亚洲 | 黄色免费视频在线观看 | 99久久精品无免国产免费 | 中文字幕 国产视频 | 免费观看黄色12片一级视频 | 中文字幕在线看片 | 欧美另类视频 | 免费在线观看av的网站 | 精品国精品自拍自在线 | 久久精品久久国产 | 99色婷婷 | 国产91精品看黄网站在线观看动漫 | 在线观看色视频 | 日韩一区视频在线 | 日日精品 | 日日爽视频| 久久精品国产v日韩v亚洲 | 韩国av不卡 | www.大网伊人| 成人影视免费 | 狠狠狠狠狠操 | 日韩亚洲在线观看 | 伊人www22综合色 | 久久99国产精品自在自在app | 国产成人精品久久亚洲高清不卡 | 日韩一区二区三区在线看 | 五月婷婷丁香色 | 国产精品视频全国免费观看 | 97精品国自产拍在线观看 | www99久久| 91精品对白一区国产伦 | 国产91亚洲| 激情五月婷婷综合 | 精品一区二区日韩 | 天天色天天操天天爽 | 国产欧美日韩精品一区二区免费 | 欧美日韩精品在线免费观看 | 国产福利91精品 | 国外成人在线视频网站 | 日韩精品中文字幕有码 | 日日日日 | 中文字幕免费 | 就要干b | 国产精品99久久免费观看 | 成人在线免费av | 精品国产一二区 | 日日干天天爽 | 麻豆首页| 99综合电影在线视频 | 成年人免费av | 日韩精品免费一线在线观看 | 免费在线观看成人 | 精品一二区 | 亚洲日本在线一区 | 综合久久婷婷 | 麻豆一区在线观看 | 日韩av成人在线 | 黄网在线免费观看 | 亚洲区视频在线观看 | 亚洲aⅴ久久精品 | 免费色av | 黄色资源网站 | 91在线91拍拍在线91 | 色姑娘综合 | 国产精品第10页 | 91精品一区国产高清在线gif | 日韩免费电影网站 | 在线观看日韩一区 | 很黄很黄的网站免费的 | 97av视频在线 | 91福利视频在线 | 国产亚洲成人网 | 亚洲成人免费在线 | 97精品国产97久久久久久免费 | 国产精品视频在线看 | 91理论片午午伦夜理片久久 | h视频日本| 免费国产在线观看 | 中文字幕在线看片 | 韩国视频一区二区三区 | 黄色大片免费播放 | 看片网站黄| 久久婷婷国产 | 久久精品国产第一区二区三区 | 免费看一级 | 一区二区三区四区影院 | 久久夜夜爽 | 久久爽久久爽久久av东京爽 | 精品主播网红福利资源观看 | 青青河边草免费直播 | 中文字幕免费看 | 亚洲在线视频网站 | 亚洲精品一区二区三区在线观看 | 亚洲黄色一级大片 | 精品久久久久一区二区国产 | 亚洲精品久久久久久国 | 免费观看视频的网站 | 亚洲区色 | 99精品一区二区三区 | 欧美久久久久久久久久久久久 | 激情综合五月天 | 伊人影院99 | 成人精品福利 | 97精品国产97久久久久久久久久久久 | 国产精品99久久久久的智能播放 | 天天综合网久久 | 五月天丁香视频 | 国产一区免费视频 | 香蕉视频免费在线播放 | 伊人五月天婷婷 | 久久精品国产亚洲a | 在线免费观看视频a | 欧美中文字幕久久 | 国产精品 999 | 99国产成+人+综合+亚洲 欧美 | 97成人精品 | 午夜成人免费影院 | 91在线视频播放 | 日韩在线网址 | 天天综合成人 | av在线之家电影网站 | 国产小视频在线免费观看 | 国产精品久久久久久69 | av夜夜操| 成人免费看片网址 | 超碰av在线播放 | 91久久国产综合精品女同国语 | 亚洲精品免费在线观看视频 | 成人av av在线 | 成人av资源网站 | 国产在线观看免费 | 日韩一级片大全 | 国产免费一区二区三区网站免费 | 国产精品永久在线 | 成年人在线免费看视频 | 欧美激情视频一二三区 | 久久久久久久久久久久久9999 | 国产一级91 | 美女在线国产 | 欧美久久久久久久久久久 | 伊人久久电影网 | 久久综合五月天婷婷伊人 | 在线小视频你懂得 | 中文字幕资源网 | 国产精品永久在线 | 亚洲精品va| 久久综合天天 | 国产99色 | 91成人在线看 | 久久视频一区二区 | 一本一本久久a久久精品牛牛影视 | 成人在线观看资源 | av在线播放中文字幕 | 高潮久久久 | 国产91区 | 四虎成人免费观看 | 91视频一8mav | wwwwww黄| 色吊丝在线永久观看最新版本 | 欧美日本三级 | 国产精品成人一区二区三区吃奶 | 韩国av免费 | 91成人精品国产刺激国语对白 | 国产精品免费在线视频 | 亚洲 精品在线视频 | 福利电影久久 | 超碰97人人干 | 中文字幕亚洲国产 | 狠狠狠狠狠狠狠干 | 在线日韩视频 | 九九免费观看视频 | 亚洲成人第一区 | 伊人网综合在线观看 | 亚洲精品视频在线免费播放 | 亚洲免费av在线播放 | 国产xxxx做受性欧美88 | 人人爽人人爽人人片av | 精品视频免费久久久看 | 国产资源网 | 成人av免费在线观看 | 综合天堂av久久久久久久 | 久精品视频在线 | 日日精品 | 成人av网页 | 免费av的网站 | 91精品久久久久久综合乱菊 | 国内精品久久久久久久97牛牛 | 成人av教育 | av中文资源在线 | 97人人澡人人爽人人模亚洲 | 91网址在线看 | 国产成人av免费在线观看 | 欧美精品久久99 | 亚洲精品久久久蜜桃 | 九九视频免费观看视频精品 | 欧美性色黄大片在线观看 | 在线免费三级 | 免费看片网址 | 99精品福利视频 | 黄色亚洲大片免费在线观看 | 成片视频免费观看 | 婷婷成人在线 | 久久伦理电影 | 99精品国产99久久久久久福利 | 日韩高清免费在线观看 | 成人av片免费观看app下载 | 午夜在线看片 | 五月婷婷激情综合网 | 欧美日韩在线精品 | 精品一区二区三区电影 | 青草视频在线 | 蜜臀av性久久久久av蜜臀三区 | 国产中文字幕视频在线观看 | 日韩视频在线观看视频 | 国产原厂视频在线观看 | 欧美成人aa| 高清av不卡 | 91在线看| 69av在线视频 | 亚洲经典视频 | 美州a亚洲一视本频v色道 | 欧美大片www | 白丝av免费观看 | 黄色的视频网站 | 久久免费片 | 中文字幕在线观看av | 91传媒激情理伦片 | 免费在线激情电影 | 91人人澡人人爽人人精品 | 狠狠狠色 | 亚洲伦理一区 | 人人模人人爽 | 久久精品视频在线 | 国产日韩欧美在线免费观看 | 射射射av | 成人免费视频a | 国产亚洲一区二区在线观看 | 91一区在线观看 | 国产电影黄色av | 久久欧美综合 | 欧美做受高潮1 | 美女性爽视频国产免费app | 日本久久免费电影 | 日本不卡123区 | 亚洲午夜精品一区二区三区电影院 | 国际精品久久久久 | 一区二区视频欧美 | 91在线看视频免费 | 亚洲黄色免费网站 | 婷婷激情影院 | 国产精品久久久久久久免费大片 | 国产 亚洲 欧美 在线 | 在线观看国产一区 | 国产精品婷婷午夜在线观看 | 一级黄色大片在线观看 | 黄色成年片 | 亚洲欧美色婷婷 | 国产精品青草综合久久久久99 | 蜜臀久久99精品久久久无需会员 | 久热电影 | 久要激情网 | 日韩av片无码一区二区不卡电影 | 成人国产精品一区 | 超碰在线人人艹 | 91女神的呻吟细腰翘臀美女 |