??????敏捷開發(fā)的理念已經(jīng)流行了很長的時(shí)間,在敏捷開發(fā)中的開發(fā)迭代階段中,我們可以通過五個(gè)步驟,來有效的提高整個(gè)項(xiàng)目的代碼質(zhì)量。
????? Java項(xiàng)目開發(fā)過程中,由于開發(fā)人員的經(jīng)驗(yàn)、Java代碼編寫習(xí)慣,以及缺乏統(tǒng)一的標(biāo)準(zhǔn)和管理流程,往往導(dǎo)致整個(gè)項(xiàng)目的代碼質(zhì)量較差,難于維 護(hù),需要較大的測(cè)試投入和周期等問題。這些問題在一個(gè)項(xiàng)目組初建、需求和設(shè)計(jì)均具有不完全可預(yù)期性和完備性的全新項(xiàng)目中將尤為突出。
????? 如圖1所示,敏捷開發(fā)過程經(jīng)歷需求調(diào)研,用例分析和用例分解,進(jìn)入開發(fā)迭代階段。在每個(gè)迭代過程中,可以采用以下步驟來保證和提高整個(gè)項(xiàng)目的代 碼質(zhì)量:統(tǒng)一編碼規(guī)范、代碼樣式;靜態(tài)代碼分析(staticcodereview);單元測(cè)試;持續(xù)集成;代碼評(píng)審和重構(gòu) (Review&Refactor)。下文將針對(duì)每個(gè)步驟和其所使用的工具、方法進(jìn)行詳細(xì)描述。
圖1.敏捷開發(fā)中的Java代碼質(zhì)量保證步驟
步驟一:統(tǒng)一編碼規(guī)范、代碼樣式
??????規(guī)范統(tǒng)一的編碼會(huì)增加項(xiàng)目代碼的可讀性和可維護(hù)性,但實(shí)際情況往往是項(xiàng)目組內(nèi)的Java代碼開發(fā)人員的編碼風(fēng)格常常各不相同,這可能是由于不同 的經(jīng)驗(yàn)習(xí)慣或者缺乏編碼規(guī)范方面的學(xué)習(xí)造成的。這樣一來,其他項(xiàng)目成員或者維護(hù)人員在閱讀項(xiàng)目代碼時(shí)就需要花費(fèi)更多的時(shí)間來理解代碼作者的意圖,所以制定 并采取統(tǒng)一的編碼規(guī)范就顯得很重要。編碼規(guī)范主要應(yīng)包含以下幾個(gè)方面:
◆一般規(guī)則和格式規(guī)范。例如代碼縮進(jìn)、程序塊規(guī)范、每行最大代碼長度等。
◆命名規(guī)則。例如包名、類名、變量、方法、接口、參數(shù)等命名規(guī)范
◆文檔規(guī)范。例如類文件頭聲明、類注釋、成員變量和方法注釋等規(guī)范。
◆編程規(guī)范。例如異常、并發(fā)、多線程等方面的處理方式。
◆其他規(guī)范。例如日志格式、屬性文件格式,返回值和消息格式。
項(xiàng)目的編碼規(guī)范可以參考已有的一些Java編程規(guī)范書籍和其他相關(guān)資料并結(jié)合項(xiàng)目的本身來制定,可供參考的書籍有《Java編程風(fēng)格》(英文書 名為:TheElementsofJavaStyle)。編碼規(guī)范要形成文檔,而且要簡(jiǎn)潔明了,并組織項(xiàng)目成員一起學(xué)習(xí),確保所有成員正確理解所有條目。
一旦編碼規(guī)范確定,就可以利用Eclipse自身提供的功能來控制代碼樣式和格式。具體做法是,點(diǎn)擊Eclipse的 Windows->Preference菜單項(xiàng),在打開的Preferences 對(duì)話 框的左側(cè)欄中找到Java節(jié)點(diǎn)下的子項(xiàng)CodeStyle(如圖2),該項(xiàng) 和它的子項(xiàng)允許您對(duì)Java代碼的樣式進(jìn)行控制。
圖2.Eclipse代碼樣式設(shè)置窗口
例如,為了使用自動(dòng)格式化工具,可以在Eclipse提供的默認(rèn)代碼格式配置的基礎(chǔ)上建立自定義的格式。在Formatter面板中,點(diǎn)擊 New,輸入新的名字并選擇一個(gè)默認(rèn)的配置作為初始化格式,如圖3所示。
圖3.創(chuàng)建新的代碼格式配置
單擊OK后就可以在新打開的窗口中進(jìn)行修改定制自己需要的格式。如圖4所示。
圖4.創(chuàng)建新的代碼格式配置
修改完成后點(diǎn)擊Apply保存所作修改。同時(shí)可以點(diǎn)擊Export將當(dāng)前的格式定義導(dǎo)出成一個(gè)XML文件,這樣項(xiàng)目組的其他成員就可以很方便通 過點(diǎn)擊圖3中的Import按鈕來導(dǎo)入該XML文件來使用同一個(gè)代碼格式定義。
這樣每次在提交代碼到版本控制 服務(wù)器 前就可以通過Eclipse界面里的Source->Format菜單來對(duì)代碼進(jìn)行格式化,從而 使整個(gè)項(xiàng)目的代碼具有相同的格式。同樣可以通過對(duì)CodeStyle下的其他項(xiàng)目進(jìn)行設(shè)置來幫助對(duì)Java代碼的樣式進(jìn)行控制。將所有這些樣式文件導(dǎo)出成 XML文件后,同編碼規(guī)范一起歸檔,供所有項(xiàng)目成員使用。
步驟二:靜態(tài)代碼分析
在完成源代碼的開發(fā)以后,下面要進(jìn)行的工作就是審視和測(cè)試代碼。除了通過運(yùn)行測(cè)試代碼來檢查功能之外,還能利用一些靜態(tài)分析工具來快速、直接地 提高代碼質(zhì)量。靜態(tài)代碼分析工具并不需要運(yùn)行代碼,可以直接對(duì)Java文件和Class文件進(jìn)行分析,通過一些檢查條件的設(shè)置,快速找到代碼中的錯(cuò)誤和潛 在缺陷。現(xiàn)在的靜態(tài)分析工具很多,有FindBugs、PMD、IBMRationalTool,等等。在這里,選擇FindBugs作為靜態(tài)代碼分析工 具。FindBugs可以和日常開發(fā)工具Eclipse進(jìn)行集成,在開發(fā)過程中,就可以方便的開始靜態(tài)代碼的檢查。通過檢查Class文件或者JAR文 件,將字節(jié)碼和一組缺陷模式進(jìn)行對(duì)比,來發(fā)現(xiàn)可能存在的代碼問題。在Eclipse的開發(fā)環(huán)境中,用插件安裝的方式安裝了Findbugs后,在 Eclipse的配置選項(xiàng)中就會(huì)多出來FindBugs的配置選項(xiàng)。可以對(duì)自己的項(xiàng)目進(jìn)行配置,選擇需要的Detector檢查代碼。
圖5.FindBugs的配置選項(xiàng)
設(shè)置好自己的規(guī)則后,在需要檢查的代碼文件夾上點(diǎn)擊右鍵,就可以啟動(dòng)FindBugs檢查。代碼可以是一個(gè)項(xiàng)目,也可以只是幾個(gè)文件。
圖6.運(yùn)行FindBugs
檢查完畢后,會(huì)出現(xiàn)FindBugs視圖,把所有檢查的結(jié)果根據(jù)錯(cuò)誤分組展示。點(diǎn)擊結(jié)果里面的每一個(gè)錯(cuò)誤,會(huì)自動(dòng)打開對(duì)應(yīng)的代碼。當(dāng)根據(jù)規(guī)則改 正了所有的錯(cuò)誤,或者說潛在錯(cuò)誤,這些代碼也就通過了靜態(tài)代碼檢查。FindBugs的檢查結(jié)果可以是XML文件,也可以是文本文件,便于項(xiàng)目的集成管理 和檢查保存。
圖7.FindBugs檢查結(jié)果
步驟三:?jiǎn)卧獪y(cè)試
單元測(cè)試用例設(shè)計(jì)和評(píng)審
單元測(cè)試是軟件開發(fā)過程中重要的質(zhì)量保證環(huán)節(jié),在此環(huán)節(jié)中,設(shè)計(jì)和評(píng)審對(duì)于保證整個(gè)單元測(cè)試過程的完整性和有效性來說十分重要。設(shè)計(jì)階段需要具 體考慮要對(duì)哪些代碼單元進(jìn)行測(cè)試,被測(cè)單元之間的關(guān)系,測(cè)試策略,以及單元測(cè)試用例設(shè)計(jì)等,并最終輸出《單元測(cè)試用例設(shè)計(jì)》文檔,用來指導(dǎo)具體的單元測(cè)試 執(zhí)行。在用例設(shè)計(jì)中,通過對(duì)代碼單元輸入和期待輸出的定義來保證該單元的功能正確性,邊界值的測(cè)試和異常測(cè)試非常重要。同時(shí)也配合測(cè)試用例和功能塊的匹配 方法來衡量用例設(shè)計(jì)的完整性。
在用例設(shè)計(jì)完成之后,下一步的工作就是進(jìn)行測(cè)試用例的評(píng)審。個(gè)人的理解和經(jīng)驗(yàn)始終是有限的,用例評(píng)審可以借集體之力,對(duì)用例設(shè)計(jì)進(jìn)入查漏補(bǔ)缺, 進(jìn)一步保證測(cè)試用例的有效性。由于單元測(cè)試屬于白盒測(cè)試范疇,它主要通過對(duì)代碼的邏輯結(jié)構(gòu)進(jìn)行分析來設(shè)計(jì)測(cè)試用例,因此,評(píng)審員的選擇最好以理解代碼邏輯 結(jié)構(gòu)為前提,如果評(píng)審員來自相關(guān) 模塊 ,還能夠有效的發(fā)現(xiàn)模塊相關(guān)性和依賴性所帶來的問題。
模擬對(duì)象技術(shù)
在實(shí)際項(xiàng)目中,開發(fā)人員自己的代碼往往需要和其他的代碼模塊或系統(tǒng)進(jìn)行交互,但在測(cè)試的過程中,這些需要被調(diào)用的真實(shí)對(duì)象常常很難被實(shí)例化,或 者這些對(duì)象在某些情況下無法被用來測(cè)試,例如,真實(shí)對(duì)象的行為無法預(yù)測(cè),真實(shí)對(duì)象的行為難以觸發(fā),或者真實(shí)對(duì)象的運(yùn)行速度很慢。這時(shí)候,就需要使用模擬對(duì) 象技術(shù)(Mock),利用一個(gè)模擬對(duì)象來模擬我們的代碼所依賴的真實(shí)對(duì)象,來幫助完成測(cè)試,提高測(cè)試覆蓋率,從而提高代碼質(zhì)量。模擬對(duì)象技術(shù)利用了在面向 接口的編程中,由于代碼直接對(duì)接口進(jìn)行調(diào)用,所以代碼并不知道引用的是真實(shí)對(duì)象還是模擬對(duì)象,這樣就可以順利的完成對(duì)代碼的測(cè)試,模擬技術(shù)有很多種,如 jMock,EasyMock,Mockito,PowerMock等等。其中Mockito消除了對(duì)期望行為的需求,避免了這些代碼的大量初始化。
圖8.Mockito示例
在模擬對(duì)象過程中,先模擬一個(gè)需要調(diào)用的List對(duì)象LinkedList,再設(shè)定這個(gè)對(duì)象的行為,當(dāng)調(diào)用get(0)的時(shí)候,返 回”first”。這樣,測(cè)試代碼就可以利用這個(gè)對(duì)象來測(cè)試我們的功能代碼,需要調(diào)用和返回值的時(shí)候,可以順利的得到模擬對(duì)象的返回值。也需要對(duì)模擬對(duì)象 進(jìn)行錯(cuò)誤情況的模擬,保證代碼對(duì)錯(cuò)誤的處理的正確性。
測(cè)試覆蓋率分析
為了衡量單元測(cè)試的質(zhì)量和覆蓋的范圍,需要對(duì)單元測(cè)試的代碼進(jìn)行測(cè)試覆蓋分析。常用的衡量測(cè)試覆蓋率的指標(biāo)主要有語句覆蓋率、分支覆蓋率、路徑 覆蓋率、條件覆蓋率和方法覆蓋率等。具體采用哪些指標(biāo)可以根據(jù)項(xiàng)目的實(shí)際情況來定,以避免因過高的指標(biāo)增加了代碼開發(fā)人員的工作量而影響了項(xiàng)目整體的進(jìn) 度。
EMMA是一款比較流行的開源Java測(cè)試覆蓋率分析工具,支持類、方法、代碼行、基本代碼塊等多種類型的測(cè)試覆蓋率分析,支持將覆蓋率分析結(jié) 果導(dǎo)出為多種格式的報(bào)告,并采用多種顏色來高亮顯示不同的覆蓋率狀態(tài)。EclEmma是一款基于EMMA的Eclipse插件,方便在 EclipseIDE中進(jìn)行測(cè)試覆蓋率分析。如圖9,在測(cè)試用例寫好后,可以在右鍵點(diǎn)擊測(cè)試類,選擇CoverageAs->JUnitTest。
圖9.運(yùn)行測(cè)試覆蓋分析
單元測(cè)試跑完后,Coverage視圖中會(huì)顯示所選擇的測(cè)試的覆蓋率。雙擊打開某一具體的類后,可以看到高亮顯示的覆蓋分析結(jié)果,如圖10所 示。紅色代表測(cè)試沒有覆蓋到該行,黃色表示部分覆蓋,綠色的行表示該行在本次測(cè)試中被覆蓋到。
圖10.查看測(cè)試覆蓋分析結(jié)果
在Coverage視圖中可以通過點(diǎn)擊鼠標(biāo)右鍵將測(cè)試覆蓋分析的結(jié)果導(dǎo)出成需要的格式,例如HTML。
圖11.導(dǎo)出測(cè)試覆蓋分析結(jié)果
圖12顯示了導(dǎo)出的report。
圖12.測(cè)試覆蓋分析報(bào)告
為了保證單元測(cè)試的有效性和質(zhì)量,可以規(guī)定一個(gè)測(cè)試覆蓋率的下限,例如所有的包和類的覆蓋率必須達(dá)到80%以上。不過值得注意的是,不要單純追 求高覆蓋率,要同時(shí)注意測(cè)試用例的質(zhì)量,如果測(cè)試用例本身就寫的有錯(cuò)誤,那么即使測(cè)試覆蓋率很高也沒有意義。
步驟四:持續(xù)集成
持續(xù)集成(ContinuousIntegration)是利用一系列的工具,方法和規(guī)則,做到快速的構(gòu)建開發(fā)代碼,自動(dòng)的測(cè)試化,來提高開發(fā) 代碼的效率和質(zhì)量。利用自動(dòng)構(gòu)建工具,隨時(shí)都能把提交的代碼構(gòu)建出來,提供一個(gè)可以測(cè)試使用的版本,讓用戶和開發(fā)人員同時(shí)看到相同的功能,盡早的發(fā)現(xiàn)問題 和錯(cuò)誤,也可以盡快的得到測(cè)試人員和用戶的反饋。
要做到持續(xù)集成,就要利用一系列工具,把開發(fā)過程中的重復(fù)工作 自動(dòng)化 。搭建自動(dòng)的構(gòu)建 服務(wù)器 , 自動(dòng)的進(jìn)行單元測(cè)試和發(fā)布新版本,一個(gè)集成的服務(wù)器可以提供構(gòu)建過程的結(jié)果報(bào)告,自動(dòng)通知開發(fā)人員構(gòu)建結(jié)果,并且保存歷史數(shù)據(jù)。 IBMRationalTeamConcert(RTC)可以提供工作任務(wù)的管理,項(xiàng)目計(jì)劃的安排,代碼版本管理控制,自動(dòng)構(gòu)建可用版本,生成構(gòu)建結(jié)果報(bào) 告。這些過程構(gòu)成了項(xiàng)目的持續(xù)集成過程,其中,版本的自動(dòng)構(gòu)建和代碼的自動(dòng)單元測(cè)試是持續(xù)集成的關(guān)鍵過程,RTC在這些過程上提供了有力的支持。
自動(dòng)構(gòu)建
RTC提供了buildengine來負(fù)責(zé)構(gòu)建build,首選,啟動(dòng)buildengine,并和RTC服務(wù)器建立了連接。再創(chuàng)建項(xiàng)目的 build定義。在這個(gè)定義中,需要設(shè)定編譯哪些 模塊 的代碼,需要跳動(dòng)哪個(gè)ANT文件來啟動(dòng)編譯,和一些編譯過程中的參數(shù)的設(shè) 定。當(dāng)這些都準(zhǔn)備好了,編譯對(duì)于項(xiàng)目而言,就變成一個(gè)簡(jiǎn)單的事情。
可以看到,通過在build定義上,點(diǎn)擊請(qǐng)求構(gòu)建,就可以觸發(fā)一次構(gòu)建過程。選擇需要的構(gòu)建參數(shù),這個(gè)過程就會(huì)在后臺(tái)運(yùn)行。每一個(gè)開發(fā)人員,做 了稍許的代碼改變和提交,都可以觸發(fā)新的構(gòu)建過程,來保證我們代碼的有效性。申請(qǐng)一個(gè)新的構(gòu)建的過程如圖13、圖14所示。
圖13.申請(qǐng)一個(gè)新的構(gòu)建
圖14.構(gòu)建申請(qǐng)界面
當(dāng)構(gòu)建結(jié)束后。RTC服務(wù)器會(huì)提供構(gòu)建結(jié)果報(bào)告。開發(fā)人員可以查詢到這次構(gòu)建的詳細(xì)信息。
圖15.構(gòu)建結(jié)果
整個(gè)開發(fā)過程中,構(gòu)建版本的過程應(yīng)該是無數(shù)次的,通過每次構(gòu)建,都可以得到當(dāng)時(shí)代碼的編譯情況,并且可以得到一個(gè)可運(yùn)行的軟件版本。在構(gòu)建定義 上,RTC支持設(shè)置構(gòu)建計(jì)劃。定時(shí)自動(dòng)的觸發(fā)一次構(gòu)建。
圖16.構(gòu)建定義
自動(dòng)單元測(cè)試
構(gòu)建可以自動(dòng)了,重點(diǎn)提高代碼質(zhì)量的單元測(cè)試呢?如果每一天的代碼,每一個(gè)版本的代碼,都已經(jīng)通過了我們的單元測(cè)試,這樣我們就能對(duì)代碼的質(zhì)量 有了基本的保證。在構(gòu)建腳本的自動(dòng)調(diào)用過程中,通過ANT的腳本,可以加上JUnit,EMMA,F(xiàn)indBugs的ANT腳本調(diào)用,每一次的構(gòu)建,都可 以把這些檢查工作自動(dòng)的進(jìn)行一遍測(cè)試。這些測(cè)試都要生成測(cè)試結(jié)果報(bào)告,RTC不能提供這些報(bào)告的展示,就可以利用Hudson這個(gè)開源工具,集成測(cè)試報(bào)告 來方便查閱。
圖17.自動(dòng)測(cè)試報(bào)告
步驟五:代碼評(píng)審和重構(gòu)
代碼評(píng)審(CodeReview)是Java項(xiàng)目開發(fā)過程中的一個(gè)重要步驟,代碼評(píng)審可以幫助發(fā)現(xiàn)靜態(tài)代碼分析過程中無法發(fā)現(xiàn)的一些問題,例如 代碼的編寫是否符合編碼規(guī)范,代碼在邏輯上或者功能上是否存在錯(cuò)誤,代碼在執(zhí)行效率和性能上是否有需要改進(jìn)的地方,代碼的注釋是否完整正確,代碼是否存在 冗余和重復(fù)。代碼評(píng)審還可以幫助新進(jìn)入項(xiàng)目組的成員快速學(xué)習(xí)和了解項(xiàng)目,促進(jìn)經(jīng)驗(yàn)分享,同時(shí)也能保證項(xiàng)目成員的良好溝通。代碼評(píng)審主要包括兩種形式,同級(jí) 評(píng)審(PeerReview)和小組評(píng)審(GroupReview)。同級(jí)評(píng)審主要指項(xiàng)目成員間的互相評(píng)審,小組評(píng)審是指通過召開評(píng)審會(huì)議,項(xiàng)目成員一起 對(duì)項(xiàng)目代碼進(jìn)行評(píng)審。
為了提高代碼評(píng)審的有效性和效率,可以借助一些外部工具,比較常用的代碼評(píng)審工具有Jupiter和CodeStriker。Jupiter是 一款開源的Eclipse插件,允許成員將評(píng)審意見定位到真實(shí)代碼的具體行,由于代碼評(píng)審的結(jié)果以XML文件的形式保存,所以可以把結(jié)果提交到版本管理 服務(wù)器 進(jìn) 行共享。圖18顯示了使用Jupiter進(jìn)行代碼評(píng)審的界面。
圖18.Jupiter代碼評(píng)審界面
在代碼評(píng)審任務(wù)創(chuàng)建后,Jupiter將代碼評(píng)審分成三個(gè)階段,個(gè)人評(píng)審階段(IndividualPhase)、團(tuán)隊(duì)評(píng)審階段 (TeamPhase)和問題修復(fù)階段(ReworkPhase)。在個(gè)人評(píng)審階段,評(píng)審成員將發(fā)現(xiàn)的代碼問題或者缺陷記錄下來,每個(gè)問題都會(huì)作為一個(gè)記 錄保存在評(píng)審表格中。在團(tuán)隊(duì)評(píng)審階段,團(tuán)隊(duì)的全部或者部分成員會(huì)一起對(duì)個(gè)人評(píng)審階段發(fā)現(xiàn)的問題進(jìn)行定性,如果問題確實(shí)存在,就將該問題分配給某個(gè)成員去解 決,并在Jupiter中將該問題設(shè)置成相應(yīng)的狀態(tài)。在問題修復(fù)階段,團(tuán)隊(duì)成員會(huì)修復(fù)屬于自己的問題,并將相應(yīng)的記錄設(shè)置成已解決等正確的狀態(tài)。
Codestriker是一款基于Web的常用代碼評(píng)審工具,對(duì)代碼的評(píng)審可以針對(duì)某一具體行,也可以針對(duì)整個(gè)代碼文件,評(píng)審意見會(huì)被保存在 數(shù)據(jù)庫 中。評(píng)審人員可以同時(shí)看到其他人的評(píng)論,代碼作者也可以針對(duì)某一具體的評(píng) 論回復(fù)。Codestriker支持郵件通知,還可以同版本控制服務(wù)器進(jìn)行集成,以跟蹤和顯示文件內(nèi)容的改變。圖19顯示了Codestriker的界 面。
圖19.Codestriker報(bào)告界面
在實(shí)踐中對(duì)所有代碼進(jìn)行小組評(píng)審會(huì)比較費(fèi)時(shí),所以可以根據(jù)實(shí)際情況來挑選一些核心代碼進(jìn)行小組評(píng)審,或者在項(xiàng)目的前期安排較多的小組評(píng)審,等項(xiàng) 目組的成員對(duì)代碼評(píng)審的標(biāo)準(zhǔn)和要求有較好的理解,進(jìn)行代碼評(píng)審的經(jīng)驗(yàn)提高后,就可以逐漸減少小組評(píng)審的次數(shù),從而達(dá)到大部分代碼即使只進(jìn)行同級(jí)評(píng)審也能保 證很好的質(zhì)量。
通過代碼評(píng)審發(fā)現(xiàn)的問題要通過代碼重構(gòu)及時(shí)解決掉,較小的不涉及多人代碼的重構(gòu)可以由項(xiàng)目成員自己借助Eclipse的重構(gòu)功能完成,不同項(xiàng)目 成員寫的實(shí)現(xiàn)相同功能的不同代碼要通過討論整合成公共的類或者方法。比較復(fù)雜的或者比較高層次的重構(gòu)工作,例如整個(gè)項(xiàng)目層面的代碼組織形式的改變需要由整 個(gè)項(xiàng)目組共同討論完成。
結(jié)論
軟件開發(fā)沒有一成不變、萬能通用的流程和方法,希望大家能從本文得到啟發(fā)和收益,結(jié)合您的實(shí)際項(xiàng)目特點(diǎn),實(shí)踐以上步驟和方法,并加以完善和改 進(jìn),共同打造高效高質(zhì)量的Java代碼,為您的項(xiàng)目成功奠定堅(jiān)實(shí)的基礎(chǔ)。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
