整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          將 75000 行原生 iOS 應用程序移植到 Flutter 后,結果太驚訝!

          CSDN編者按】很少有文章,介紹如何將大型應用,移植到Flutter。而本文的作者——一位來自澳洲的Native iOS & Flutter的開發(fā)者,嘗試這樣做了,結果讓他十分驚訝。到底是什么情況?一起來看文章吧!

          澳大利亞有一個名為Easy Diet Diary的原生iOS應用程序。

          該應用:

          ? 已被下載120萬次;

          ? 用Objective-C和Swift編寫,后端是Amazon AWS;

          ? 代碼統(tǒng)計工具CLOC,報告該應用包含75,000行代碼。

          我在這家小公司工作了很長一段時間,他們的任務列表上一直有個安卓版本,但我們一直沒有開發(fā),因為:

          ? 支持兩個代碼庫需要太多精力且難以管理。

          ? 跨平臺開發(fā)的主要選擇Xamarin和React Native都有重要缺陷(這是另一個故事)。

          最后,我們選擇進入Flutter的世界!

          Flutter的速度很快,并且可以保證用戶界面體驗,而且一切都與原生應用沒有區(qū)別(特別是有了2018年9月加入的iOS小窗體之后)。

          以下是本文的主干:

          ? 代碼行數(shù)與開發(fā)速度

          ? 架構

          ? 社區(qū)

          ? 性能

          ? 語言

          ? 還缺少什么?

          ? 結論

          1代碼行數(shù)與開發(fā)速度

          第一階段我預估需要6個人月。但是,項目進度居然領先了!對我來說,這簡直太不可思議了。

          為什么?

          Flutter的布局并不是像iOS那樣,使用的不是Storyboard,或者像安卓那樣使用XML,而是在代碼中將窗體組合成窗體樹,即可創(chuàng)建應用程序的用戶界面。這對我來說聽起來有點可怕,但是我做了嘗試,雖然花了一些時間來習慣,但不久我就可以靈活地使用這些窗體樹了。

          然后,大約第一個階段進展到第三個月的時候,發(fā)生了一件很奇怪的事情。隨著我越來越熟練、越來越快地移植功能,項目中的代碼行卻開始迅速減少了。這很奇怪,因為我移植的業(yè)務邏輯數(shù)量非常龐大,這些邏輯在代碼數(shù)量上的比例幾乎是一比一。

          事情的真相是,我可以通過創(chuàng)建類和編寫函數(shù)來重用用戶界面部分的代碼,這比使用原生iOS更容易。通常,我可以利用幾個額外的參數(shù),簡單地重構用戶界面的窗體就可以重用它們。如果這樣不行,我還可以簡單地在現(xiàn)有的窗體周圍再包上另一個窗體,就可以實現(xiàn)需要的行為了。這簡直太贊了!

          最終我預計代碼行數(shù)將少于30,000(而原生iOS版本為75,000行)。當然,原生iOS版本包含一些雖然當時開發(fā)了最終卻被取代或未被使用的代碼。我估計未使用的代碼占15,000行。換句話說,需要移植的代碼量為60,000行。

          因此,總的來說,F(xiàn)lutter的代碼量只有原生iOS原有代碼的一半!

          此外,F(xiàn)lutter項目不包含任何Storyboard XML。Storyboard中有很多XML。原生iOS項目包含:

          ? 15個Storyboard;

          ? 47個Nib文件;

          ? 92個View Controllers。

          我與Storyboard斗爭了很多年,一直在嘗試遵循最佳實踐,最后感覺在Flutter中構建用戶界面非常自由而且速度很快。

          以前我沒有意識到自己的大部分時間都用在了編寫與用戶界面相關的代碼,還要忍受大量的Storyboard和自動布局限制。

          我無數(shù)次聽人說應該將用戶界面布局與代碼分開,我非常同意,但就我的Flutter經驗而言,這一點未必是真的。而且關于用戶界面分離的這種概念也不僅僅是原生iOS的最佳實踐。

          我記得自己在微軟WPF中與XML作斗爭,也見過Quora上有人問《為什么安卓使用XML來定義用戶界面而不僅僅是Java代碼?》

          Storyboard是一種自上至下的布局方式(適用于桌面應用程序),而窗體采用自下而上的方法,在構建移動應用程序時,窗體可以極大地簡化編程。我聽說這種方式類似于React Native和CSS flex-boxes的布局方式。Wm Leler在Hacker Noon上發(fā)表的文章《Flutter帶來了哪些創(chuàng)新》很好地解釋了這個問題。

          以下方式對于利用窗體構建用戶界面很有幫助性:

          ? 大多數(shù)情況下,F(xiàn)lutter中支持狀態(tài)的“熱重載”功能可以在幾秒鐘內,將代碼更改無縫地整合到正在運行的應用程序中;

          ? Android Studio的快捷鍵Alt + Enter可以插入或刪除用戶界面的窗體(行、列或容器)。請查看這篇文章《使用Android Studio開發(fā)Flutter應用程序的小竅門》(https://medium.com/@liewjuntung/tips-on-using-android-studio-to-develop-flutter-apps-9e42c047b7f4)。

          我覺得VS Code中應該有類似的東西。這似乎微不足道,但我覺得這個快捷鍵十分有用。使用熱重載和Alt + Enter,我可以在幾分鐘內做好一個畫面,甚至可以在用戶界面上做實驗。

          ? 將debugPaintSizeEnabled設置為true。這會在所有用戶界面的窗體周圍顯示鮮艷的邊框。實際上這個功能用得并不如想象得多,但是當布局出現(xiàn)問題時該功能確實非常有用。

          2架構

          我在選擇架構時做了如下幾件事:

          ? 看了幾遍Brian Egan的這個演講《保持簡單、有狀態(tài):Flutter應用的架構》(https://www.youtube.com/watch?v=zKXz3pUkw9A&feature=youtu.be)。

          ? 讀了幾遍Eric Windmill的這篇文章《有效地使用Flutter的繼承窗體》(https://ericwindmill.com/posts/inherited_widget/)。

          ? 閱讀Flutter架構示例:http://fluttersamples.com/。

          最終,我按照Eric的建議使用了一種名為Lifting State Up的架構模式,這是Redux的第一步,看起來非常誘人。然而,Redux對我來說遙不可及。由于開發(fā)時間緊迫,學習和嘗試Redux似乎太令人生畏了。

          一路走來,我從Stack Overflowers上的人解答的關于架構的問題中得到了許多幫助。這讓我想到了社區(qū)。

          3社區(qū)

          有關Flutter的開源社區(qū)非常多元化,并且非常樂于助人,讓我看到了人類的希望(特別是在這些瘋狂的時期)。

          舉個例子,當時我正在使用Romain Rastel編寫的flutter_slidable軟件包,而且我還提了一個改善建議,僅僅48小時之內他就實現(xiàn)了一個比我想象的更好的解決方案......類似這樣的事情比比皆是。

          我唯一遺憾的是,我一直忙于移植工作,與我收到的幫助相比,我給予別人的遠遠不夠。

          4性能

          總的來說,參加了內部測試的用戶對Flutter的“活潑”非常滿意。在同一臺iOS設備上,同時并排運行iOS應用與Flutter應用時,并沒有看到性能明顯下降。

          我們的應用沒有很多需要大量圖形的任務,但有一個功能需要從數(shù)百個JSON文件讀取數(shù)據(jù),然后對該數(shù)據(jù)進行一系列浮點計算,在該功能中Flutter的應用明顯更快。

          我沒有花時間去研究導致差異的究竟是是讀取文件的功能、還是JSON解析或者是日期處理等等,因此我無法做出類別上的判斷,但我感覺這無疑是Flutter桂冠上的一顆明珠。

          很期待看到其他人能給出怎樣的性能測試數(shù)據(jù)。

          5語言

          Flutter使用Dart,這種語言已經在Google之外萎靡不振,直到最近才隨著Flutter再次興起。

          然而,這門語言很成熟且易于學習。幸運的是,我在加入Dart隊伍時,擁有更強大的類型功能的Dart 2.0剛剛出現(xiàn),所以無需再在代碼中不斷地敲“new”關鍵字了。

          Dart可能沒有Swift和Kotlin所擁有的Null和非Null類型,但我很喜歡它的簡單性。 例如:

          ? 以下劃線開頭的函數(shù)為私有;

          ? 自動格式化意味著不必再頭疼我的習慣問題——我喜歡在末尾加上逗號將參數(shù)分行;

          ? 包管理很簡單。

          還有很多很多。我喜歡這些功能,也許其他人可能不喜歡。對我而言,最重要的是我可以更快地(用奇怪但很愉悅的方式)實現(xiàn)功能。

          6還缺少什么?

          沒有太多缺少的東西。在原生iOS應用中:

          ? 我在XCode中使用了很多Targets,并結合一堆#define創(chuàng)建bundle ID不同的各種版本的應用。我不知道在Flutter中怎么處理這個問題;

          ? 我在iOS中使用了一個很好的第三方日志框架,叫做CocoaLumberjack。還沒找到能代替它的東西;

          ? 我使用UIKit框架中的WKWebView來加載并渲染本地的HTML文件(如使用條款、隱私政策等)。我在Flutter中沒找到正確的包來實現(xiàn)這個功能。最后只能使用一個包HTML2MD將HTML轉換成Markdown再使用另一個包flutter_markdown來渲染;

          ? 我使用AVFoundation框架,在單一的全屏視圖中實現(xiàn)條碼掃描、QR二維碼掃描和拍照。在Flutter中我還不能如此細致地進行控制,雖然它的Camera包很適合拍照,另一個由facundomedica編寫的包fast_qr_reader_view很適合掃描條碼。在安卓設備上,這個包與Firebase的ML Kit配合從Camera包中獲取實時圖像。

          7結論

          讀到這里,你肯定不會驚訝為什么我如此贊美Flutter。到目前為止:

          ? Flutter的用戶界面幾乎與原生安卓和原生iOS的用戶界面沒有區(qū)別;

          ? 得益于Flutter用戶界面的構建方式,利用Flutter制作新功能比原生代碼更快;

          ? 測試沒有收到有關性能劣化的報告;

          ? iOS版和安卓版之間的代碼共享目前達到了90%以上。我還沒有集成蘋果的HealthKit或Google Fit,但我覺得共享率應該不會下降太多。

          盡管Flutter還不成熟(2018年5月才發(fā)布正式版),但對于我來說它已經足夠強壯了。

          我遇到的唯一問題就是Dart同步讀取目錄的函數(shù)List Sync在最近的一次發(fā)布中出現(xiàn)了崩潰。我將它加到了Flutter在Github上的代碼庫中,然后改用異步版本。

          原文:https://medium.com/flutter-community/porting-a-75-000-line-native-ios-app-to-flutter-57c6571c57b4

          作者:Gary Hunter,Native iOS & Flutter的開發(fā)者。

          譯者:彎月,責編:胡巍巍

          “征稿啦!”

          CSDN 公眾號秉持著「與千萬技術人共成長」理念,不僅以「極客頭條」、「暢言」欄目在第一時間以技術人的獨特視角描述技術人關心的行業(yè)焦點事件,更有「技術頭條」專欄,深度解讀行業(yè)內的熱門技術與場景應用,讓所有的開發(fā)者緊跟技術潮流,保持警醒的技術嗅覺,對行業(yè)趨勢、技術有更為全面的認知。

          如果你有優(yōu)質的文章,或是行業(yè)熱點事件、技術趨勢的真知灼見,或是深度的應用實踐、場景方案等的新見解,歡迎聯(lián)系 CSDN 投稿,聯(lián)系方式:微信(guorui_1118,請備注投稿+姓名+公司職位),郵箱(guorui@csdn.net)。

          ypora 是一款支持實時預覽的 Markdown 文本編輯器。它有 OS X、Windows、Linux 三個平臺的版本,目前完全免費

          https://typora.io/#

          Markdown是一種輕量級標記語言,創(chuàng)始人為約翰·格魯伯(英語:John Gruber)。 它允許人們使用易讀易寫的純文本格式編寫文檔,然后轉換成有效的XHTML(或者HTML)文檔。這種語言吸收了很多在電子郵件中已有的純文本標記的特性。

          由于Markdown的輕量化、易讀易寫特性,并且對于圖片,圖表、數(shù)學式都有支持,目前許多網站都廣泛使用Markdown來撰寫幫助文檔或是用于論壇上發(fā)表消息。 如GitHub、Reddit、Diaspora、Stack Exchange、OpenStreetMap 、SourceForge、簡書等,甚至還能被使用來撰寫電子書。

          在使用Dreamweaver編寫網頁時,遇到需要插入代碼塊、流程圖、數(shù)學公式時,總是顯得很無力,效率很低,效果不好,使用Typora會讓這些問題迎刃而解,且輕便,簡單。

          直接看一個demo:

          導出為html:

          html網頁源代碼:

          其可以導出的格式有:

          流程圖樣式包括:

          1、標準流程圖源碼格式(橫向):

          ```flow
          st=>start: 開始框
          op=>operation: 處理框
          cond=>condition: 判斷框(是或否?)
          sub1=>subroutine: 子流程
          io=>inputoutput: 輸入輸出框
          e=>end: 結束框
          st(right)->op(right)->cond
          cond(yes)->io(bottom)->e
          cond(no)->sub1(right)->op
          ```

          2 mermaid語言庫繪流程圖

          Mermaid 是一個用于畫流程圖、狀態(tài)圖、時序圖、甘特圖的庫,使用 JS 進行本地渲染,廣泛集成于許多 Markdown 編輯器中。

          Mermaid 作為一個使用 JS 渲染的庫,生成的不是一個“圖片”,而是一段 HTML 代碼,因此安全許多。

          官網:https://mermaidjs.github.io/
          Github 項目地址:https://github.com/knsv/mermaid

          2.1 橫向流程圖源碼格式:

          graph LR
          A[方形] -->B(圓角)
              B --> C{條件a}
              C -->|a=1| D[結果1]
              C -->|a=2| E[結果2]

          2.2 豎向流程圖源碼格式:

          sequenceDiagram
          Title: 標題:復雜使用
          對象A->對象B: 對象B你好嗎?(請求)
          Note right of 對象B: 對象B的描述
          Note left of 對象A: 對象A的描述(提示)
          對象B-->對象A: 我很好(響應)
          對象B->小三: 你好嗎
          小三-->>對象A: 對象B找我了
          對象A->對象B: 你真的好嗎?
          Note over 小三,對象B: 我們是朋友
          participant C
          Note right of C: 沒人陪我玩

          2.3 時序圖源碼復雜樣例

                  gantt
                  dateFormat  YYYY-MM-DD
                  title 軟件開發(fā)甘特圖
                  section 設計
                  需求                      :done,    des1, 2014-01-06,2014-01-08
                  原型                      :active,  des2, 2014-01-09, 3d
                  UI設計                     :         des3, after des2, 5d
              未來任務                     :         des4, after des3, 5d
                  section 開發(fā)
                  學習準備理解需求                      :crit, done, 2014-01-06,24h
                  設計框架                             :crit, done, after des2, 2d
                  開發(fā)                                 :crit, active, 3d
                  未來任務                              :crit, 5d
                  耍                                   :2d
                  section 測試
                  功能測試                              :active, a1, after des3, 3d
                  壓力測試                               :after a1  , 20h
                  測試報告                               : 48h

          2.4 甘特圖樣例:

                  gantt
                  dateFormat  YYYY-MM-DD
                  title 軟件開發(fā)甘特圖
                  section 設計
                  需求                      :done,    des1, 2014-01-06,2014-01-08
                  原型                      :active,  des2, 2014-01-09, 3d
                  UI設計                     :         des3, after des2, 5d
              未來任務                     :         des4, after des3, 5d
                  section 開發(fā)
                  學習準備理解需求                      :crit, done, 2014-01-06,24h
                  設計框架                             :crit, done, after des2, 2d
                  開發(fā)                                 :crit, active, 3d
                  未來任務                              :crit, 5d
                  耍                                   :2d
                  section 測試
                  功能測試                              :active, a1, after des3, 3d
                  壓力測試                               :after a1  , 20h
                  測試報告                               : 48h


          教程:

          Markdown 高級技巧 | 菜鳥教程(使用 Typora 編輯器講解 Markdown 的語法)

          https://www.runoob.com/markdown/md-advance.html

          ref

          1 Typora 完全使用詳解

          https://sspai.com/post/54912/

          2 用什么軟件畫流程圖好?-悟空問答

          https://www.wukong.com/question/6809962012198568195/

          3 Mermaid 實用教程

          https://blog.csdn.net/fenghuizhidao/article/details/79440583

          -End-


          關工具:

          1.PyMuPdf 組件, python組件包,含mupdf的核心功能并與mutool功能兼容

          PyMuPDFpypi.org/project/PyMuPDF/#files

          備選: FreePic2Pdf.exe 第三方PDF書簽管理工具,可直接提取PDF文檔目錄

          2.Python SDK包及PyCharm開發(fā)工具(PyCharm只需下載社區(qū)版本即可)

          Welcome to Python.orgwww.python.org/

          PyCharm: the Python IDE for Professional Developers by JetBrainswww.jetbrains.com/pycharm/

          相關操作:

          提取pdf的索引目錄: 有多種方法,常見的如: 1.直接拷貝目錄/OCR識別目錄 2.PDF閱讀器自帶獲取目錄 3.通過zotero和zotfile的提取功能 4.devonthink來創(chuàng)建TOC 5.通過FreePic2Pdf第三方提取軟件 6.通過mutool命令行工具包 都可以實現(xiàn), 這里放幾張展示圖:

          • 獲取PDF目錄(不需要Python):

          方法一:mutool工具執(zhí)行命令行獲取TOC方法二:mutool run javascript腳本來獲取方法三:FreePic2Pdf等第三方提取軟件

          如上所示: 我們提供的多種方法都可以不依賴Python實現(xiàn)提取PDF目錄,但為了后續(xù)的文章技術進階,以及操作流程自動化,我們在本文開始引入python來實現(xiàn)我們的需求.因此這里我們采用的是PyMuPdf來實現(xiàn).具體的下載鏈接已放置于文章開頭.

          • 獲取PDF目錄(使用了Python)

          步驟一:配置基礎的開發(fā)環(huán)境

          Python的安裝比較簡單,官網下載安裝包雙擊安裝即可,因此本文不再詳細講解,(只是要注意本文我們要下載大于2.7的版本來使用,如果你的python環(huán)境有問題,請和我的3.9版本保持一致)

          到官網下載后雙擊安裝

          上面安裝好python環(huán)境后,接著我們來安裝PyMuPDF Python組件包,相關幫助文檔可參考如下:

          https://pypi.org/project/PyMuPDF/#filespypi.org/project/PyMuPDF/#files

          按python版本二種方式選一種來安裝

          PyMuPDF Documentation - PyMuPDF 1.18.6 documentationpymupdf.readthedocs.io/en/latest/

          這里我們選擇的是下載whl包安裝按自己系統(tǒng)下載,我下載的是macos-cp39

          按上面方式2下載whl文件并雙擊安裝Mupdf Python組件后,接著我們開始配置PyCharm開發(fā)工具, 用最前面的鏈接下載PyCharm軟件并設置好PyCharm的Python SDK版本,具體如下所示:

          確保用的是Python3的SDK

          步驟二: 編寫Python代碼,執(zhí)行生成HTML:
          ## 提取章節(jié)信息import fitz # = PyMuPDFpdfName = "java2.pdf"doc = fitz.open(pdfName) # open PDFtoc = doc.getToC() # get current table of contentswith open("chapter-t.html", mode="w", encoding="utf-8") as f:
           for t in toc:
           t[2] = pdfName + "-" + str(t[2]) # show what we have so far
           chapterInfo = "{}{}-{}{}".format("<p>", t[1], t[2], "</p>
          ")
            print(chapterInfo)
           f.write(chapterInfo)

          用IE瀏覽器打開上面生成的HTML,用Ctrl+Shift+A導入至SuperMemo進行Split命令分割,如圖:

          IE瀏覽器打開展示效果SM中使用自定義符號來分割PDF索引目錄導入SM操作最終的索引目錄導入效果

          步驟三: 開始PDF文檔的增量學習

          我們對上面的分支添加學習計劃并Ctrl+L開始學習,同樣左側排列SM軟件,右側排列PDF閱讀器: 提示: 取消SuperMemo軟件的窗口背景選項,才能進行如下二個軟件的左右布局
          • 當復習到對應的元素時打開PDF(PDF學習)

          基于Alfred/AHK/Quicker來編寫腳本,實現(xiàn)搜索并打開PDF,接著按頁或章節(jié)內容跳轉到指定章節(jié)

          按PDF索引數(shù)據(jù)打開PDF基于PDF索引的增量閱讀

          • 添加/檢索/及批量管理注釋書簽(PDF提取)

          使用福昕閱讀器的注釋功能PDF注釋添加/刪除/管理(PDF提取)

          • 增量提取的子注釋同步回SM軟件(提取同步)

          因為我們的PDF內容提取是在PDF閱讀器中實現(xiàn)的,為了能使提取的文章內容也能在SM軟件中增量,我們考慮同步回SM軟件中,這個操作可按自己的需求或頻次來決定,不一定非得同步回SM軟件.

          同步回SM時唯一要注意的是最好不要覆蓋掉原來同步過的子元素內容(確保保留學習進度) 具體如何避免這個問題我在文章末尾會有較詳細的概述及相關方法.

          用福昕來閱讀只能導出文本注釋

          提示 : 上面導出的福昕閱讀器內容注釋我們處理如下,接著再導入SuperMemo進行Split分割:

          自己手動處理下段落分割符號

          上面的注釋文本復制進SuperMemo軟件,再使用Split命令分割就是按段落內容正確的分割了.

          導入SuperMemo來分割處理最終處理結果(PDF提取同步)

          如上所述: 整個PDF增量閱讀提取流程結束.以后我們只需重復執(zhí)行這些步驟來閱讀即可.你可以參考我之前寫的一篇內容來了解基于PDF目錄索引來進行增量學習PDF文件的流程(鏈接如下):

          一只小胖子:流程-SuperMemo增量學習及間隔復習12 贊同 · 10 評論文章

          主要講解的是Mac系統(tǒng)下使用DevonThink及PDFExpert閱讀器來實現(xiàn)SuperMemo增量學習的整體思路.如果你用的是Windows系統(tǒng),那么你可以使用Everything/FileLocator Pro 工具代替DevonThink的功能,使用福昕閱讀器或者BookxNote閱讀器來代替PDFExpert的功能.

          考慮到要支持注釋中含有圖片的問題,我推薦在Mac操作系統(tǒng)下使用Highlights PDF閱讀器,在Windows下使用BookxNote閱讀器.如果還不能滿足你特定的需求,則建議用本文的PyMuPdf組件編寫一些簡單的Python代碼,來實現(xiàn)更復雜及更自由化的需求.


          • Mac系統(tǒng)下的Highlights演示:

          Mac下的Highlights閱讀器靈活豐富的注釋導出功能

          由于html導出的是base64的圖片存儲,因此建議導出TextBundle(本地圖片|markdown)格式:

          導出成markdown再轉成html

          說明:

          如上所示,如果是MAC系統(tǒng)使用Highlight作為PDF閱讀器,導出注釋時. 第一種可以直接拷貝右側的注釋內容至SuperMemo中,第二種則是導出右側注釋為TextBundle格式(圖片本地存儲)并把md文件轉換成Html(如果直接Highlights導出為Html注釋筆記,里面的圖片為base64編碼,不能在SuperMemo直接導入)再導入SuperMemo.

          TextBundle對應為本地圖片和md

          ## MarkDown -> Htmlpandoc text.md -o text1.html


          • Windows下BookxNote的演示:

          下圖為BookxNote閱讀器的功能演示,可在Windows下作為代替Mac端Highlights軟件部分功能:

          Windows下BookxNote演示

          步驟四: 提取內容同步回SM軟件時保留學習進度

          通過Python腳本來實現(xiàn)進度同步功能,流程上依賴于時間戳標記(不同于官方默認的按ID同步),即閱讀時在PDF文件中通過文本注釋的形式添加時間戳標識作為書簽,閱讀中斷后,我們會按上面的方式導出注釋,作為書簽使用的這個時間戳會在導出的注釋(最終的html)中存在,這個html導入SuperMemo分割時,用此時間戳作為分割符號,即生成了每個元素都有了一個時間戳作為唯一ID使用.因此在重復導入的多個不同的集合中(跨集合)我們也可以遷移舊的學習進度至新集合.

          PDF閱讀加時間戳作書簽及分割符腳本使用腳本來實現(xiàn)學習進度同步功能該圖所示的網盤下載地址在評論區(qū)


          完結:

          以上進度同步功能的具體操作,后期會考慮直接錄制視頻來演示.因此本文不再繼續(xù)對細節(jié)進行說明. 說明: 上圖的腳本下載鏈接詳見評論區(qū)...


          我是一只熱愛學習的小胖子,如果你也熱愛學習,并且對SuperMemo感興趣,歡迎轉發(fā)和評論!


          主站蜘蛛池模板: 亚洲一区精品伊人久久伊人| 免费萌白酱国产一区二区| 国产精品538一区二区在线| 日韩精品一区二区三区老鸭窝 | 国产一区二区在线观看app| 精品人伦一区二区三区潘金莲| 亚洲一区二区三区无码影院| 亚洲福利秒拍一区二区| 亚洲av乱码一区二区三区| 亚洲性日韩精品国产一区二区| 国产日韩精品一区二区在线观看播放| 91在线一区二区三区| 国产a∨精品一区二区三区不卡| 国产精品被窝福利一区| 国产日韩精品一区二区三区| 亚洲国产一区二区三区| 日韩一区二区三区四区不卡| 在线精品亚洲一区二区| 精品无码一区二区三区在线 | 国产精品福利一区| 久久综合亚洲色一区二区三区| 亚洲国产高清在线一区二区三区 | 国产精品乱码一区二区三区| 日本美女一区二区三区 | 高清国产精品人妻一区二区| 精品无码成人片一区二区| 国产一区二区三区福利| 国产人妖视频一区二区破除| 精品视频在线观看一区二区三区| 日韩美一区二区三区| 国产一区二区三区樱花动漫| 精品一区二区三区无码视频| 国产福利电影一区二区三区,亚洲国模精品一区| 深田咏美AV一区二区三区| 午夜一区二区在线观看| 乱色精品无码一区二区国产盗| 日本一道高清一区二区三区| 亚洲色欲一区二区三区在线观看| 精品亚洲综合在线第一区| 久久人妻无码一区二区| 成人影片一区免费观看|