成都app開發(fā)已步入App 工廠時代

2022-07-16    分類: App開發(fā)

App工廠,是根據(jù)一個具有完備組件庫以及這些組件的依賴關(guān)系,組合成一個個App。在多App場景下,由于存在一套代碼,按需生成不同App所需要的代碼,原有的架構(gòu)、代碼依賴關(guān)系、工程代碼組織方式都需要相應(yīng)的改變。而現(xiàn)在,成都app開發(fā)已經(jīng)逐步進入app工廠時代。



業(yè)務(wù)的快速試錯催生多App


移動互聯(lián)網(wǎng)不論是在上半場,還是在下半場,業(yè)務(wù)的創(chuàng)新從來沒有停歇過。從微博到團購,從共享汽車到共享單車,從長視頻到短視頻,業(yè)務(wù)和模式的創(chuàng)新不斷。近幾年尤以頭條系的業(yè)務(wù)試錯見諸于各報端,從資訊到直播,再到短視頻,是一波接一波。


當前不論是大的互聯(lián)網(wǎng)公司,還是創(chuàng)業(yè)性的小公司,要想在新的領(lǐng)域摸索出一番天地,必須不斷試錯。移動領(lǐng)域的業(yè)務(wù)不斷試錯,要求能快速產(chǎn)出各業(yè)務(wù)對應(yīng)的創(chuàng)新App。


集團業(yè)務(wù)的逐步擴大與細化催生多App


互聯(lián)網(wǎng)江湖早已三分天下,巨頭已經(jīng)建立,大的互聯(lián)網(wǎng)平臺很難形成。但越是大的互聯(lián)網(wǎng)平臺,越擔心垂直細分業(yè)務(wù)的進攻。為應(yīng)對進攻,集團業(yè)務(wù)也需要在一些領(lǐng)域逐步擴大和細化,垂直App應(yīng)運而生。


垂直App與創(chuàng)新App的差距在于,垂直App是基于現(xiàn)有平臺業(yè)務(wù)細分而來,而創(chuàng)新App是平臺業(yè)務(wù)所沒有的。


另外,為了應(yīng)對應(yīng)用市場的分發(fā)和對包大小敏感的用戶,這幾年極速包幾乎成為各大公司的必備App。


集團業(yè)務(wù)的合并融合催生多App交叉


業(yè)務(wù)的收購、合并也是大型互聯(lián)網(wǎng)公司常有的事。收購合并后的業(yè)務(wù)如何融合,如何既能保持業(yè)務(wù)的獨立性,又能節(jié)省集團研發(fā)資源,還能支持一套交叉業(yè)務(wù)(又稱垂直業(yè)務(wù))代碼在各獨立App運行,是一個重要又復(fù)雜的問題。比如今年集團內(nèi)安居客房產(chǎn)業(yè)務(wù)和原房產(chǎn)業(yè)務(wù)的融合就是一個典型的案例。


App工廠的實施目標


1.App工廠有以下目標:


標準化能力的產(chǎn)出,為App研發(fā)提效增速


標準化能力是實現(xiàn)App工廠的基礎(chǔ),標準化能力與App業(yè)務(wù)代碼無耦合關(guān)系,比如React Native SDK,網(wǎng)絡(luò)庫、緩存庫等。


支持創(chuàng)新App、垂直App、極速App的生成和迭代


同一套代碼,根據(jù)配置,能按需生成不同App所需的代碼。按需生成是關(guān)鍵和核心,不給App工廠生成的App代碼攜帶任何無用代碼,增加包大小。


支持垂直業(yè)務(wù)在獨立App上的平移


App工廠依附于App框架代碼上,馬甲包、極速包與App工廠(App)是一個子集與全集的關(guān)系。但類似安居客App與App是兩個獨立App,有交集(公共底層代碼或某些業(yè)務(wù)代碼),業(yè)務(wù)代碼集合不一樣。


針對獨立App的公共業(yè)務(wù)代碼,定義為垂直業(yè)務(wù)。App工廠在統(tǒng)一底層服務(wù)的前提下,也要支持垂直業(yè)務(wù)在獨立App上的平移。即一套業(yè)務(wù)代碼,能在兩個或多個獨立App上運行。


App工廠架構(gòu)


PODS


在iOS領(lǐng)域,pods特指cocoapods,是其縮寫。cocoapods是對OC或swift Cocoa 工程的依賴管理。(CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. )


中間件


中間件在軟件領(lǐng)域的通用解釋是:連接軟件組件和應(yīng)用的程序。在這里中間件體現(xiàn)的是連接和共用。連接的是業(yè)務(wù)層和基礎(chǔ)庫層,共用體現(xiàn)在業(yè)務(wù)層的公共服務(wù)。


中間件按照業(yè)務(wù)強相關(guān)與否分為業(yè)務(wù)中間件和標準中間件。


業(yè)務(wù)中間件:與業(yè)務(wù)強相關(guān)的中間件,在某一個獨立App中通用。由于對當前App其它功能的過多依賴,所以不適用于其他獨立App。


標準中間件:與業(yè)務(wù)弱相關(guān)的中間件,不僅在某一個獨立App中通用,在其它獨立App中也通用,與App中的業(yè)務(wù)弱相關(guān)。最常見的是標準版的RNSDK。


基礎(chǔ)庫


對其它pod不產(chǎn)生依賴的獨立庫。比如一些開源的三方庫,是常見的基礎(chǔ)庫。除了第三方開源的,集團內(nèi)自封裝的sdk,如果對其它pod不產(chǎn)生依賴,也可以歸入基礎(chǔ)庫范圍,比如Passport SDK,WPush SDK等;


入口工程


主要負責對App工廠生成的App所需代碼進行配置。


入口工程pods:主要負責對App工廠生成的App所需代碼進行配置,入口工程中包括的功能有:


APPInfo:對App基礎(chǔ)信息的設(shè)置,比如App名稱,bundle identifier,版本號,證書等;


Podfile:當前App對所需工程代碼的依賴,比如招聘馬甲包會依賴招聘業(yè)務(wù)pod以及其他基礎(chǔ)服務(wù)pod和三方庫pod;


Regen.sh: 一個可執(zhí)行文件(本地RD研發(fā)調(diào)試用),讀取podfile配置,拷貝App所需代碼及配置,然后生成App所需代碼;


Reng_jenkins.sh: 一個可執(zhí)行文件(Jenkins服務(wù)打包用),讀取podfile配置,拷貝App所需代碼及配置,然后生成App所需代碼;


工程庫池


工程池是App工廠總的pod代碼集合。


工程池是App工廠總的代碼集合,每一個生成App所需代碼都是從這個代碼集合中獲取,研發(fā)過程中代碼更新也會同步更新到此代碼集合中去。


業(yè)務(wù)pods:各獨立業(yè)務(wù)工程代碼,代碼集合根據(jù)業(yè)務(wù)類型來劃分,比如App首頁pod、房產(chǎn)pod、招聘pod;


中間件pods:App工廠中間服務(wù)代碼,是自己封裝的,區(qū)別于外界的第三方公開代碼,故稱為中間件代碼。中間件根據(jù)對App業(yè)務(wù)的是否強依賴分為:


業(yè)務(wù)中間件:與App業(yè)務(wù)強相關(guān),但是是App中業(yè)務(wù)中通用中間服務(wù),其應(yīng)用場景在App的業(yè)務(wù)場景內(nèi)。


標準中間件:與App業(yè)務(wù)弱相關(guān),可以作為一個標準化中間件在其它獨立App上引入。在標準中間件中可以看到有圖標加了兩條豎線,這表示此標準中間件某些功能的實現(xiàn)依賴接入App的實現(xiàn),只開放了接口協(xié)議。以RN基礎(chǔ)庫標準中間件為例:中間件包含的內(nèi)容是載體頁及熱更新的全部公共的與業(yè)務(wù)弱相關(guān)的內(nèi)容,但對于一些擴展的組件(比如埋點)需要開放協(xié)議讓接入方實現(xiàn),中間件中不實現(xiàn)此邏輯。


三方庫pods:外界的開源第三方庫代碼,基本在行業(yè)內(nèi)有統(tǒng)一的引用標準;


在架構(gòu)設(shè)計上,各層pods的依賴準則為:


上層可以依賴下層,但下層不可以依賴上層。比如上層中的業(yè)務(wù)pod中的首頁(MainPage)可以依賴業(yè)務(wù)中間件中的生命周期(WBLifeCircle),但反之不能依賴。


可以隔層依賴。比如業(yè)務(wù)pod可以依賴基礎(chǔ)庫pod;


業(yè)務(wù)pod間不能產(chǎn)生依賴。比如房產(chǎn)pod不能依賴招聘pod。


中間件pod和三方庫pod可以單向依賴。比如RN所在pod可以對登錄服務(wù)所在pod產(chǎn)生單向依賴。


制定上述依賴準則,是為了在生產(chǎn)App時或者進行垂直業(yè)務(wù)平移時可以按需配置所需pod。


如何借助App工廠架構(gòu)達成設(shè)計目標


1.如何提供標準化的能力


所謂標準化能力,可以理解為獨立無依賴的Framework或SDK,對應(yīng)上述架構(gòu)圖中的標準中間件。比如RN基礎(chǔ)庫,封裝了載體頁、熱更新等一整套公共服務(wù),App外的獨立App可以無縫接入。


另外,還有一些集團內(nèi)其他中臺部門提供的標準化SDK,比如PassportSDK、IMSDK、PaySDK等。


2.如何支持創(chuàng)新App、極速App的生成


在理想工程架構(gòu)狀態(tài)下(即達到架構(gòu)各層依賴準則),可以按需配置App所需功能,來生成馬甲包或者極速包。當然為了應(yīng)對蘋果審核(App之間必須保持差異性),還得針對馬甲包或者極速包來做一些個性化的處理。這種個性化處理在先前的馬賽克項目有完成,具體詳見馬賽克項目。


3.如何支持垂直業(yè)務(wù)的平移


垂直業(yè)務(wù):同一業(yè)務(wù)在多個App上呈現(xiàn)的業(yè)務(wù)稱之為垂直業(yè)務(wù)。


垂直業(yè)務(wù)平移:并不是真的去移動,是指垂直業(yè)務(wù)及依賴的底層代碼是一套公共代碼,能夠運行在不同App上。


上圖所示的是租房和二手房這兩個垂直業(yè)務(wù)需要達到一套代碼,同時運行在App和安居客App上。這就要求:


App和安居客App共用垂直業(yè)務(wù)所依賴的底層代碼(中間件代碼+基礎(chǔ)庫代碼);


垂直業(yè)務(wù)代碼及所依賴的底層代碼對App或安居客App中的獨有代碼沒有任何耦合,這樣就不會攜帶一些無關(guān)的不需要的代碼,有利于控制包大??;


垂直業(yè)務(wù)代碼及所依賴的底層代碼必須滿足App工廠架構(gòu)中的分層原則和依賴原則,這樣架構(gòu)擴展性會比較靈活


如何對存量代碼實施App工廠?


基于前文App工廠技術(shù)架構(gòu)及各層pod的依賴準則,各層pod的依賴關(guān)系理想示意圖如下圖所示(以招聘業(yè)務(wù)pod依賴為例):


從業(yè)務(wù)層到中間件層再到基礎(chǔ)庫層,從上到下單向依賴,沒有反向依賴和循環(huán)依賴


業(yè)務(wù)層之間沒有依賴


中間件層和基礎(chǔ)庫層可以允許有單向依賴


有了上述理想的依賴關(guān)系后,在入口工程進行生成App所需代碼進行配置時,就能按需配置,不會因為pod之間的反向依賴、循環(huán)依賴、整層依賴攜帶很多無用代碼,增加包大小。


1. 業(yè)務(wù)層pod解耦


上圖所示的招聘業(yè)務(wù)的依賴關(guān)系。黑色箭頭表示的是pod的單向依賴,紅色的雙向箭頭表示的pod的雙向依賴。


備注:服務(wù)層對應(yīng)中間件層,三方庫層對應(yīng)基礎(chǔ)庫層。


針對業(yè)務(wù)pod解耦主要處理下層pod對業(yè)務(wù)pod的依賴以及業(yè)務(wù)pod之間的依賴,如下圖所示:


2. 中間件層pod解耦


如上圖中實線所示的是招聘pod所依賴的中間件層pod之間的耦合關(guān)系。


服務(wù)層pod解耦要解決以下兩種耦合關(guān)系:


pod之間的雙向耦合


pod之間的不必要單向依賴


服務(wù)層pod的解耦至關(guān)重要,直接涉及到對工具庫pod的依賴處理。如不解除服務(wù)層pod的循環(huán)依賴關(guān)系,則會導(dǎo)致對工具庫pod的整層依賴,沒法按需配置所依賴的pod,造成包大小無法控制。


3. 基礎(chǔ)庫層pod解耦


由于基礎(chǔ)庫層pod是最底層pod,沒有其他的依賴pod,所以也是這三層pod解耦工作量最少的。


目前App內(nèi)的基礎(chǔ)庫層pod全都是放在一個pod中,這層解耦所要作的是按照功能對這個pod進行拆分,拆成一個個上層pod可依賴的單元。


如何保證APP工廠質(zhì)量?


App工廠的質(zhì)量在版本迭代過程中的質(zhì)量非常重要。如果在后續(xù)版本迭代過程中代碼沒有嚴格遵循App工廠的pod依賴準則,等到發(fā)現(xiàn)問題才去解決,會帶來很大的額外工作量。


1. Pod依賴關(guān)系檢測


這個是所有質(zhì)量檢測的基礎(chǔ)。在本文看到的一些pod的依賴關(guān)系都是我們開發(fā)的pod依賴自動分析工具得出的。如果沒有這個工具,在一些中大型的App中,靠人工方式去梳理這種依賴關(guān)系,將是一個極大的工作量。在這里大概說一下思路,有更好的方式歡迎交流:


掃描本地工程目錄下所有pod代碼文件夾,及里面的類文件,建立類文件與pod工程的映射關(guān)系 filePodDict。


掃描每一個pod下面類文件中的文件依賴部分(import部分),根據(jù)頭文件依賴及上面的filePodDict,建立pod的直接依賴關(guān)系podDepenDict。


串聯(lián)所有pod的直接依賴關(guān)系,形成pod依賴最終關(guān)系podFinalDepenGraph,并輸出。最終Pod的依賴關(guān)系對應(yīng)的數(shù)據(jù)結(jié)構(gòu)是有向圖。


如上圖所示,是基于招聘pod和其依賴的pod構(gòu)建的有向圖的示意圖(為便于識別,將兩個pod直接相互依賴的一條線畫成了虛線)。基于這個數(shù)據(jù)結(jié)構(gòu),能實現(xiàn)前文所說的App工廠依賴準則的檢測。


2. 下層Pod對上層pod反向依賴檢測


下層pod對上層pod反向依賴,是App工廠依賴準則首要禁止內(nèi)容。比如如果中間件層的WubaRN的這個pod依賴了上層 首頁pod,會導(dǎo)致在業(yè)務(wù)平移過程中因為依賴WubaRN,而需攜帶不需要的首頁業(yè)務(wù)代碼。


基于上述的有向圖,反向檢測在技術(shù)上很容易實現(xiàn):


內(nèi)置一份pod與層級的映射關(guān)系


遍歷pod依賴關(guān)系有向圖,檢測當前pod所依賴的pod層級是否小于自己的層級,如果小于,則是反向依賴,并標記


將標記的反向依賴關(guān)系輸出


3. Pod循環(huán)依賴檢測


在App工廠中,除了業(yè)務(wù)層代碼有非常明確的原因不能有依賴和環(huán)外,其它層的pod之間即使存在環(huán),也有辦法達到App工廠不攜帶多余代碼的目標。但撇開App工廠不說,環(huán)的存在本質(zhì)上是大多數(shù)情況兩個pod之間存在公共代碼沒有下沉。所以為了使App工廠的依賴準則更簡單和更易執(zhí)行,就統(tǒng)一規(guī)定不能產(chǎn)生循環(huán)依賴。


檢測有向圖是否存在環(huán),是一個基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)問題,在此不贅述。


4. 標準中間件污染檢測


標準中間件是App工廠的核心,如果標準中間件在后續(xù)的業(yè)務(wù)迭代過程中被污染,即引入了不符合準則的依賴關(guān)系,將帶來額外的維護成本和解耦成本。所以如果能在單分支研發(fā)的時候以及集成分支上進行檢測,將被污染的概率降到最低。


在App工廠中,標準中間件只允許依賴基礎(chǔ)庫層的pod。所以檢測策略也很簡單:


遍歷所有標準中間件


遍歷每一個標準中間件所依賴的pod,并判斷所依賴的pod是否屬于基礎(chǔ)庫層。如果不屬于,則標記這個被污染的依賴關(guān)系。


輸出所有被污染的標準中間件及不合規(guī)的依賴關(guān)系。


App工廠的實踐經(jīng)驗


App工廠在App上有著廣泛的應(yīng)用。目前已在房產(chǎn)垂直業(yè)務(wù)平移和招聘垂直App生成上進行了應(yīng)用,并上線。


房產(chǎn)垂直業(yè)務(wù)平移實踐(木星計劃項目)


從去年開始,同城房產(chǎn)業(yè)務(wù)和安居客房產(chǎn)業(yè)務(wù)進行了調(diào)整,租房和二手房業(yè)務(wù)在兩個獨立App上進行了重新拆分和整合。業(yè)務(wù)調(diào)整后原來的同城租房和安居客二手房業(yè)務(wù)變成了垂直業(yè)務(wù),即在同城App和安居客App兩個獨立App上同時運行。業(yè)務(wù)的調(diào)整給技術(shù)架構(gòu)帶來了很大的挑戰(zhàn):


如何將同城租房、安居客二手房從原有App中拆分出來?


如何在拆分過程中處理依賴代碼,大限度降低攜帶無關(guān)代碼?


可以想象一下,如果不基于App工廠要達成上述目標,會出現(xiàn)什么情況?


要么攜帶很多對方App所不需要的,或者重復(fù)的代碼,造成包大小失控。


要么針對具體業(yè)務(wù)寫非常多的協(xié)議(Protocol),各獨立App針對協(xié)議做各自實現(xiàn)。但這個協(xié)議會非常多,尤其針對存量代碼的改造成本非常高。


于是,無線技術(shù)部與房產(chǎn)技術(shù)部(安居客房產(chǎn)技術(shù)部、房產(chǎn)技術(shù)部)一拍即合,就將App工廠應(yīng)用到房產(chǎn)垂直業(yè)務(wù)平移中。


1.項目里程碑


這里重點介紹一下項目里程碑,以說明在多App垂直業(yè)務(wù)平移過程中,接入App工廠的思路。


從上述表格及依賴關(guān)系可以看出項目主要分為三個階段:


抽離出垂直業(yè)務(wù)所依賴的公共庫


各App分別接入抽出的公共庫


垂直業(yè)務(wù)做一些適配,能同時運行在雙App上


第一個階段公共庫的抽離大概用了1個半月;第二個階段各獨立App接入公共庫用了1-2個版本(平均3個星期一個版本),主要看測試資源的情況;第三個階段垂直業(yè)務(wù)平移用了2-3個版本。


2.項目實施概述


2.1 公共庫的抽離


這里的公共庫是指垂直業(yè)務(wù)所依賴的中間件層代碼庫和基礎(chǔ)庫層代碼庫。這一步非常重要,如果沒有處理到位,后續(xù)業(yè)務(wù)在接入的過程中會不斷返工。


具體垂直業(yè)務(wù)對中間件代碼和基礎(chǔ)庫代碼的耦合分析上文已詳細介紹了,在此不重復(fù)描述。這里要討論一個實踐中很重要的問題:從兩個獨立App中抽離公共庫,如何統(tǒng)一的問題?


這個問題很復(fù)雜,以網(wǎng)絡(luò)中間件為例,各獨立App都有自己的封裝,而且封裝的API差異很大,很難通過調(diào)整API協(xié)議去抹平差異。這種情況下最簡單高效的方法是以一方App為基準,另一方App提兼容需求并放棄原有自己的代碼,抽離出來后共同維護。


考慮到App的體量和對業(yè)務(wù)的影響,當時商量的是以App為基準,安居客根據(jù)二手房業(yè)務(wù)代碼的調(diào)用需求,提兼容需求。App抽離出來后,安居客重新接入。


最終剝離出的公共庫(標準中間件)如下表所示:


關(guān)于公共庫的剝離有兩個關(guān)鍵點要注意:


以要平移的業(yè)務(wù)所依賴的公共庫為核心,不要貪多。以業(yè)務(wù)驅(qū)動來剝離公共庫,隨著業(yè)務(wù)的逐步接入和不斷支持,公共庫的數(shù)量和能力也逐漸上去了。


技術(shù)上剝離公共庫不難,難的是大限度降低對其它業(yè)務(wù)的影響,以及保證關(guān)聯(lián)業(yè)務(wù)上線的穩(wěn)定性。


如前文架構(gòu)中介紹的,公共庫有標準中間價和業(yè)務(wù)中間件。在這里沒有具體介紹業(yè)務(wù)中間件的情況。因為業(yè)務(wù)中間件的依賴關(guān)系比較復(fù)雜。在具體拆分時一定要詳細分析拆分成本。


2.2 各獨立App接入公共庫


下表列舉了實施過程中的其中有代表性的四個中間件在各獨立App上的接入方案。


由于是基于App抽離出的中間件,所以App租房代碼在平移的過程中,業(yè)務(wù)代碼基本不用改動。但安居客的業(yè)務(wù)代碼需要做相應(yīng)的改動,這個成本是節(jié)省不了的。從當前上線的安居客二手房功能代碼穩(wěn)定性來看,這個部分改動很成功。


2.3 垂直業(yè)務(wù)平移


上述垂直業(yè)務(wù)依賴的公共庫在各個獨立App接入后,并不意味著垂直業(yè)務(wù)就可以平移了。App工廠的一個核心目標是不攜帶無關(guān)代碼。垂直業(yè)務(wù)除了對公共庫有依賴,還對自身App中的其它模塊代碼有依賴。只有大限度對這些非公共庫代碼摘除依賴,即拆分成業(yè)務(wù)中間件,才能真正滿足App工廠目標。


這里不具體敘述如何去解藕業(yè)務(wù)中間件,主要介紹一下操作過程中的幾個準則,只要把握好這個準則,基本沒什么大的問題:


分析依賴代碼能否做成業(yè)務(wù)中間件。業(yè)務(wù)中間件一定要滿足前文敘述的單向依賴原則,否則在代碼攜帶過程中無法做分析。


如果依賴代碼只是少數(shù)幾個文件,不足以拆分出業(yè)務(wù)中間件。在對包大小沒有影響的前提下可以允許一些重復(fù)代碼。


拆分業(yè)務(wù)中間件的過程中一定要保證對其它業(yè)務(wù)線不要產(chǎn)生影響。比如房產(chǎn)和招聘都依賴一塊業(yè)務(wù)中間件代碼,那在滿足房產(chǎn)業(yè)務(wù)平移的過程中,要想辦法不要對招聘代碼產(chǎn)生影響。


對常見的解藕手段一定要注意選型,比如什么場景該用通知,什么場景該用runtime,什么場景該用protocol。


3.項目成果


這個項目是三方一起共同完成的,在這里僅說無線iOS側(cè)的一些成果:


上述成果只涵蓋了App工廠標準化成果,這些標準化成果不僅僅支持房產(chǎn)垂直業(yè)務(wù)平移,還適用于對其它業(yè)務(wù)的支持,比如同城招聘App(已完成)、同城租房App(即將進行)的生成和部落垂直業(yè)務(wù)平移(正在進行)。關(guān)于業(yè)務(wù)中間件的解耦與具體業(yè)務(wù)有關(guān)聯(lián),在此沒有詳細梳理。


App工廠在木星計劃中對包大小的收益及接入后的穩(wěn)定性如下表所示:


從上表可以看出,包大小上不論是對App還是安居客App,都有非常大的收益。崩潰率在接入前后沒有顯著性變化,代碼上線穩(wěn)定表現(xiàn)良好。特別是針對崩潰率和功能穩(wěn)定性,涉及這么大范圍的變動,能做到?jīng)]有線上事故確實不容易。


同城招聘App(創(chuàng)新App)生成實踐


創(chuàng)新App、極速版App都是同一類型的App,大部分基礎(chǔ)功能都可以使用App工廠基礎(chǔ)能力。由于蘋果在馬甲包審核規(guī)則上的限制,功能的相似度超過一定程度會有較大的審核風險。所以不論是創(chuàng)新App還是極速版App,基于蘋果審核的限制,肯定不能百分生成所需要的代碼,有一部分代碼需要額外開發(fā)。至于額外開發(fā)的代碼需要占多大比例,沒有確定答案,能向

分享名稱:成都app開發(fā)已步入App 工廠時代
鏈接分享:http://www.muchs.cn/news4/179704.html

網(wǎng)站建設(shè)、網(wǎng)絡(luò)推廣公司-創(chuàng)新互聯(lián),是專注品牌與效果的網(wǎng)站制作,網(wǎng)絡(luò)營銷seo公司;服務(wù)項目有App開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計