前言
在如今的 Fultter 大潮下,本系列是讓你看完會(huì)安心的文章。本系列將完整講述:如何快速?gòu)?開(kāi)發(fā)一個(gè)完整的 Flutter APP,配套高完成度
Flutter 開(kāi)源項(xiàng)目GSYGithubAppFlutter。同時(shí)也會(huì)提供一些Flutter的開(kāi)發(fā)細(xì)節(jié)技巧,并針對(duì)開(kāi)發(fā)過(guò)程中可能遇到的問(wèn)題進(jìn)行填坑。
系列文章分為三篇,第一部分是基礎(chǔ)篇(針對(duì)Dart語(yǔ)言和Flutter基礎(chǔ)),第二部分是App快速開(kāi)發(fā)實(shí)戰(zhàn)篇,第三部分是細(xì)節(jié)填坑篇。
筆者相繼開(kāi)發(fā)過(guò) 的跨平臺(tái)兼容性無(wú)疑最好。前期開(kāi)發(fā)調(diào)試完全在 Android 端進(jìn)行的情況下,第一次在 IOS
平臺(tái)運(yùn)行居然沒(méi)有任何錯(cuò)誤,并且還沒(méi)出現(xiàn)UI兼容問(wèn)題,相信對(duì)于經(jīng)歷過(guò)跨平臺(tái)開(kāi)發(fā)的猿們而言,這是多么的不可思議畫(huà)面。并且 Fluuter 的 HotLoad
相比較其他兩個(gè)平臺(tái),也是絲滑的讓人無(wú)法相信。吹爆了!
這些特點(diǎn)其實(shí)這得益于Flutter Engine 和 Skia
,如果有興趣的可以看看筆者之前的《移動(dòng)端跨平臺(tái)開(kāi)發(fā)的深度解析》。好了,感慨那么多,讓我們進(jìn)入正題吧。
一、基礎(chǔ)篇
1、環(huán)境搭建
Flutter 的環(huán)境搭建十分省心,特別對(duì)應(yīng) Android 開(kāi)發(fā)者而言,只是在 Android Stuido 上安裝插件,并下載flutter
Sdk到本地,配置在環(huán)境變量即可。其實(shí)中文網(wǎng)的搭建Futter開(kāi)發(fā)環(huán)境已經(jīng)很貼心詳細(xì),從平臺(tái)指引開(kāi)始安裝基本都不會(huì)遇到問(wèn)題。
這里主要是需要注意,因?yàn)槟承┎豢煽沽Φ脑颍瑖?guó)內(nèi)的用戶(hù)需要配置 Flutter 的代理,并且國(guó)內(nèi)用戶(hù)在搜索 Flutter 第三方包時(shí),也是在
https://pub.flutter-io.cn 內(nèi)查找,下方是需要配置到環(huán)境變量的地址。(ps Android Studio下運(yùn)行 IOS 也是蠻有意思的)
///win直接配置到環(huán)境編輯即可,mac配置到bash_profile export PUB_HOSTED_URL=https:
//pub.flutter-io.cn //國(guó)內(nèi)用戶(hù)需要設(shè)置 export FLUTTER_STORAGE_BASE_URL=https:
//storage.flutter-io.cn //國(guó)內(nèi)用戶(hù)需要設(shè)置
2、Dart語(yǔ)言下的Flutter
在跨平臺(tái)開(kāi)領(lǐng)域被 JS 一統(tǒng)天下的今天,Dart 語(yǔ)言的出現(xiàn)無(wú)疑是一股清流。作為后來(lái)者,Dart語(yǔ)言有著不少Java、kotlin 和 JS
的影子,所以對(duì)于 Android 原生開(kāi)發(fā)者、前端開(kāi)發(fā)者而言無(wú)疑是非常友好的。
官方也提供了包括IOS開(kāi)發(fā)者,React Native 等開(kāi)發(fā)者遷移到 Flutter 上的文檔,所以請(qǐng)不要擔(dān)心,Dart語(yǔ)言不會(huì)是你掌握 Flutter
的門(mén)檻。甚至作為開(kāi)發(fā)者,就算你不懂 Dart 也可以看著代碼摸索。
Come on,下面主要通過(guò)對(duì)比,簡(jiǎn)單講述下 Dart 的一些特性,主要涉及的是 Flutter 下使用。
基本類(lèi)型
var 可以定義變量,如?var tag = "666"?,這和 JS 、 Kotlin 等語(yǔ)言類(lèi)似,同時(shí) Dart 屬于動(dòng)態(tài)類(lèi)型語(yǔ)言,支持閉包。
Dart 中 number 類(lèi)型分為?int?和?double?,其中 java 中的 long 對(duì)應(yīng)的也是 Dart 中的 int 類(lèi)型。Dart 中沒(méi)有
float 類(lèi)型。
Dart 下只有 bool 型可以用于 if 等判斷,不同于 JS 這種使用方式是不合法的?var g = "null"; if(g){}?。
DART中,switch 支持 String 類(lèi)型。
變量
Dart 不需要給變量設(shè)置?setter getter?方法, 這和 kotlin 等類(lèi)似。Dart 中所有的基礎(chǔ)類(lèi)型、類(lèi)等都繼承 Object ,默認(rèn)值是
NULL, 自帶 getter 和 setter ,而如果是 final 或者 const 的話,那么它只有一個(gè) getter 方法。
Dart 下的數(shù)值,在作為字符串使用時(shí),是需要顯式指定的。比如:int i = 0; print("aaaa" + i);?這樣并不支持,需要?
print("aaaa" + i.toString());?這樣使用。這和 Java 與 JS 存在差異。所以在使用動(dòng)態(tài)類(lèi)型時(shí),需要注意不要把 number
類(lèi)型當(dāng)做 String 使用。
DART 中數(shù)組等于列表,所以?var list = [];?和?List list = new List()?可以簡(jiǎn)單看做一樣。
方法
Dart 下????、??=?屬于操作符,如:?AA ?? "999"?表示如果 AA 為空,返回99;AA ??= "999"?表示如果 AA 為空,給
AA 設(shè)置成 99。
可以指定或者不指定。調(diào)用效果:?getRepositoryDetailDao(“aaa", "bbbb", branch: "dev");
Dart 不像 Java ,沒(méi)有關(guān)鍵詞 public 、private 等修飾符,_下橫向直接代表 private ,但是有?@protected?注解。
Dart 中多構(gòu)造函數(shù),可以通過(guò)如下代碼實(shí)現(xiàn)的。默認(rèn)構(gòu)造方法只能有一個(gè),而通過(guò)Model.empty()
?方法可以創(chuàng)建一個(gè)空參數(shù)的類(lèi),其實(shí)方法名稱(chēng)隨你喜歡。而變量初始化值時(shí),只需要通過(guò)?this.name?在構(gòu)造方法中指定即可:
class ModelA { String name; String tag;
//默認(rèn)構(gòu)造方法,賦值給name和tag ModelA(this.name, this.tag);
//返回一個(gè)空的ModelA ModelA.empty();
//返回一個(gè)設(shè)置了name的ModelA ModelA.forName(this.name); }
Flutter
Flutter 中支持?async/await?。這一點(diǎn)和 ES7 很像,如下代碼所示,只是定義的位置不同。同時(shí)異步操作也和 ES6 中的Promise
?很像,只是 Flutter 中返回的是?Future?對(duì)象,通過(guò)?then?可以執(zhí)行下一步。如果返回的還是?Future?便可以?then().then.()
?的流式操作了 。
///模擬等待兩秒,返回OK request() async { await Future.delayed(Duration(seconds: 1));
return "ok!"; }
///得到"ok!"后,將"ok!"修改為"ok from request" doSomeThing() async { String data =
await request(); data = "ok from request"; return data; }
///打印結(jié)果 renderSome() { doSomeThing().then((value) { print(value); ///輸出ok
from request }); }
Flutter 中?setState?很有 React Native 的既視感,F(xiàn)lutter 中也是通過(guò) state
跨幀實(shí)現(xiàn)管理數(shù)據(jù)狀態(tài)的,這個(gè)后面會(huì)詳細(xì)講到。
Flutter 中一切皆 Widget 呈現(xiàn),通過(guò)?build方法返回 Widget,這也是和 React Native 中,通過(guò)?render
函數(shù)返回需要渲染的 component 一樣的模式。
3、Flutter Widget
在 Flutter 中,一切的顯示都是 Widget 。Widget 是一切的基礎(chǔ),作為響應(yīng)式的渲染,屬于 MVVM 的實(shí)現(xiàn)機(jī)制。我們可以通過(guò)修改數(shù)據(jù),再用
setState?設(shè)置數(shù)據(jù),F(xiàn)lutter 會(huì)自動(dòng)通過(guò)綁定的數(shù)據(jù)更新 Widget 。所以你需要做的就是實(shí)現(xiàn) Widget 界面,并且和數(shù)據(jù)綁定起來(lái)。
Widget 分為 兩種,在 Flutter 中每個(gè)頁(yè)面都是一幀。無(wú)狀態(tài)就是保持在那一幀。而有狀態(tài)的 Widget 當(dāng)數(shù)據(jù)更新時(shí),其實(shí)是繪制了新的
Widget,只是 State 實(shí)現(xiàn)了跨幀的數(shù)據(jù)同步保存。
這里有個(gè)小 Tip ,當(dāng)代碼框里輸入?stl?的時(shí)候,可以自動(dòng)彈出創(chuàng)建無(wú)狀態(tài)控件的模板選項(xiàng),而輸入?stf?的時(shí),就會(huì)彈出創(chuàng)建有狀態(tài) Widget
的模板選項(xiàng)。
代碼格式化的時(shí)候,括號(hào)內(nèi)外的逗號(hào)都會(huì)影響格式化時(shí)換行的位置。
如果覺(jué)得默認(rèn)換行的線太短,可以在設(shè)置-Editor-Code Style-Dart-Wrapping and Braces-Hard wrap at
設(shè)置你接受的數(shù)值。
3.1、無(wú)狀態(tài)StatelessWidget
直接進(jìn)入主題,下方代碼是無(wú)狀態(tài) Widget 的簡(jiǎn)單實(shí)現(xiàn)。
繼承 StatelessWidget,通過(guò)?build?方法返回一個(gè)布局好的控件??赡墁F(xiàn)在你還對(duì) Flutter 的內(nèi)置控件不熟悉,but?Don't
worry , take is easy?,后面我們就會(huì)詳細(xì)介紹。這里你只需要知道,一個(gè)無(wú)狀態(tài)的 Widget 就是這么簡(jiǎn)單。
Widget 和 Widget 之間通過(guò)?child:?進(jìn)行嵌套。其中有的 Widget 只能有一個(gè) child,比如下方的?Container?;有的
Widget 可以多個(gè) child ,也就是children:,比如` Colum 布局。下方代碼便是 Container Widget 嵌套了 Text
Widget。
import 'package:flutter/material.dart';
class DEMOWidget extends StatelessWidget { final String text;
//數(shù)據(jù)可以通過(guò)構(gòu)造方法傳遞進(jìn)來(lái) DEMOWidget(this.text);
@override Widget build(BuildContext context) { //這里返回你需要的控件
//這里末尾有沒(méi)有的逗號(hào),對(duì)于格式化代碼而已是不一樣的。 return Container( //白色背景 color: Colors.white,
//Dart語(yǔ)法中, 表示如果text為空,就返回尾號(hào)后的內(nèi)容。 child: Text(text "這就是無(wú)狀態(tài)DMEO"), ); } }
3.2、有狀態(tài)StatefulWidget
繼續(xù)直插主題,如下代碼,是有狀態(tài)的widget的簡(jiǎn)單實(shí)現(xiàn)。
你需要?jiǎng)?chuàng)建管理的是主要是?State?, 通過(guò) State 的?build?方法去構(gòu)建控件。在 State 中,你可以動(dòng)態(tài)改變數(shù)據(jù),這類(lèi)似 MVVM
實(shí)現(xiàn),在?setState?之后,改變的數(shù)據(jù)會(huì)觸發(fā) Widget 重新構(gòu)建刷新。而下方代碼中,是通過(guò)延兩秒之后,讓文本顯示為 "這就變了數(shù)值"。
如下代碼還可以看出,State 中主要的聲明周期有 :
?●??initState?:初始化,理論上只有初始化一次,第二篇中會(huì)說(shuō)特殊情況下。
?●??didChangeDependencies:在 initState 之后調(diào)用,此時(shí)可以獲取其他 State 。
?●??dispose?:銷(xiāo)毀,只會(huì)調(diào)用一次。
看到?jīng)],F(xiàn)lutter 其實(shí)就是這么簡(jiǎn)單!你的關(guān)注點(diǎn)只要在:創(chuàng)建你的?StatelessWidget?或者?StatefulWidget?而已。
你需要的就是在?build?中堆積你的布局,然后把數(shù)據(jù)添加到 Widget 中,最后通過(guò)?setState?改變數(shù)據(jù),從而實(shí)現(xiàn)畫(huà)面變化。
import 'dart:async'; import 'package:flutter/material.dart';
class DemoStateWidget extends StatefulWidget {
final String text;
////通過(guò)構(gòu)造方法傳值 DemoStateWidget(this.text);
///主要是負(fù)責(zé)創(chuàng)建state @override _DemoStateWidgetState createState() =>
_DemoStateWidgetState(text); }
class _DemoStateWidgetState extends State<DemoStateWidget> {
String text;
_DemoStateWidgetState(this.text);
@override void initState() { ///初始化,這個(gè)函數(shù)在生命周期中只調(diào)用一次 super.initState(); ///定時(shí)2秒
new Future.delayed(const Duration(seconds: 1), () { setState(() { text =
"這就變了數(shù)值"; }); }); }
@override void dispose() { ///銷(xiāo)毀 super.dispose(); }
@override void didChangeDependencies() { ///在initState之后調(diào) Called when a
dependency of this [State] object changes. super.didChangeDependencies(); }
@override Widget build(BuildContext context) { return Container( child:
Text(text"這就是有狀態(tài)DMEO"), ); } }
4、Flutter 布局
Flutter 中擁有需要將近30種內(nèi)置的 布局Widget,其中常用有
Container、Padding、Center、Flex、Stack、Row、Colum、ListView 等,下面簡(jiǎn)單講解它們的特性和使用。
類(lèi)型 作用特點(diǎn)
Container 只有一個(gè)子 Widget。默認(rèn)充滿(mǎn),包含了padding、margin、color、寬高、decoration 等配置。
Padding 只有一個(gè)子 Widget。只用于設(shè)置Padding,常用于嵌套child,給child設(shè)置padding。
Center 只有一個(gè)子 Widget。只用于居中顯示,常用于嵌套child,給child設(shè)置居中。
Stack 可以有多個(gè)子 Widget。 子Widget堆疊在一起。
Colum 可以有多個(gè)子 Widget。垂直布局。
Row 可以有多個(gè)子 Widget。水平布局。
Expanded 只有一個(gè)子 Widget。在 Colum 和 Row 中充滿(mǎn)。
ListView 可以有多個(gè)子 Widget。自己意會(huì)吧。 ?●??Container :最常用的默認(rèn)布局!只能包含一個(gè)child:,支持配置
new Container( ///四周10大小的maring margin: EdgeInsets.all(10.0), height: 120.0,
width:500.0, ///透明黑色遮罩 decoration: new BoxDecoration( ///弧度為4.0
borderRadius: BorderRadius.all(Radius.circular(4.0)),
///設(shè)置了decoration的color,就不能設(shè)置Container的color。 color: Colors.black, ///邊框
border:new Border.all(color: Color(GSYColors.subTextColor), width: 0.3)),
child:new Text("666666")); ??●??Colum、Row 絕對(duì)是必備布局,
橫豎布局也是日常中最常見(jiàn)的場(chǎng)景。如下方所示,它們常用的有這些屬性配置:主軸方向是 start 或 center 等;副軸方向方向是 start 或
center 等;mainAxisSize 是充滿(mǎn)最大尺寸,或者只根據(jù)子 Widget 顯示最小尺寸。
//主軸方向,Colum的豎向、Row我的橫向 mainAxisAlignment: MainAxisAlignment.start,
//默認(rèn)是最大充滿(mǎn)、還是根據(jù)child顯示最小大小 mainAxisSize: MainAxisSize.max,
//副軸方向,Colum的橫向、Row我的豎向 crossAxisAlignment :CrossAxisAlignment.center,
?●??Expanded 在 Colum 和 Row 中代表著平均充滿(mǎn),當(dāng)有兩個(gè)存在的時(shí)候默認(rèn)均分充滿(mǎn)。同時(shí)頁(yè)可以設(shè)置?flex?屬性決定比例。
new Column( ///主軸居中,即是豎直向居中 mainAxisAlignment: MainAxisAlignment.center,
///大小按照最小顯示 mainAxisSize : MainAxisSize.min, ///橫向也居中 crossAxisAlignment :
CrossAxisAlignment.center, children: <Widget>[ ///flex默認(rèn)為1 new Expanded(child:
new Text("1111"), flex: 2,), new Expanded(child: new Text("2222")), ], );
接下來(lái)我們來(lái)寫(xiě)一個(gè)復(fù)雜一些的控件。首先我們創(chuàng)建一個(gè)私有方法_getBottomItem,返回一個(gè)?Expanded Widget
,因?yàn)楹竺嫖覀冃枰獙⑦@個(gè)方法返回的 Widget 在 Row 下平均充滿(mǎn)。
如代碼中注釋?zhuān)季謨?nèi)主要是現(xiàn)實(shí)一個(gè)居中的Icon圖標(biāo)和文本,中間間隔5.0的 padding:
///返回一個(gè)居中帶圖標(biāo)和文本的Item _getBottomItem(IconData icon, String text) { ///充滿(mǎn) Row
橫向的布局 return new Expanded( flex: 1, ///居中顯示 child: new Center( ///橫向布局 child:
new Row( ///主軸居中,即是橫向居中 mainAxisAlignment: MainAxisAlignment.center,
///大小按照最大充滿(mǎn) mainAxisSize : MainAxisSize.max, ///豎向也居中 crossAxisAlignment :
CrossAxisAlignment.center, children: <Widget>[ ///一個(gè)圖標(biāo),大小16.0,灰色 new Icon(
icon, size: 16.0, color: Colors.grey, ), ///間隔 new Padding(padding: new
EdgeInsets.only(left:5.0)), ///顯示文本 new Text( text, //設(shè)置字體樣式:顏色灰色,字體大小14.0
style:new TextStyle(color: Colors.grey, fontSize: 14.0), //超過(guò)的省略為...顯示
overflow: TextOverflow.ellipsis, //最長(zhǎng)一行 maxLines: 1, ), ], ), ), ); }
接著我們把上方的方法,放到新的布局里。如下流程和代碼:
?●??首先是?Container包含了Card,用于快速簡(jiǎn)單的實(shí)現(xiàn)圓角和陰影。
?●??然后接下來(lái)包含了FlatButton實(shí)現(xiàn)了點(diǎn)擊,通過(guò)Padding實(shí)現(xiàn)了邊距。
?●??接著通過(guò)Column垂直包含了兩個(gè)子Widget,一個(gè)是Container、一個(gè)是Row。
?●??Row 內(nèi)使用的就是_getBottomItem方法返回的 Widget ,效果如下圖。
@override Widget build(BuildContext context) { return new Container( ///卡片包裝
child:new Card( ///增加點(diǎn)擊效果 child: new FlatButton( onPressed: (){print("點(diǎn)擊了哦"
);}, child: new Padding( padding: new EdgeInsets.only(left: 0.0, top: 10.0,
right:10.0, bottom: 10.0), child: new Column( mainAxisSize: MainAxisSize.min,
children: <Widget>[ ///文本描述 new Container( child: new Text( "這是一點(diǎn)描述", style:
TextStyle( color: Color(GSYColors.subTextColor), fontSize: 14.0, ), ///
最長(zhǎng)三行,超過(guò) ... 顯示 maxLines: 3, overflow: TextOverflow.ellipsis, ), margin: new
EdgeInsets.only(top:6.0, bottom: 2.0), alignment: Alignment.topLeft), new
Padding(padding: EdgeInsets.all(10.0)),
///三個(gè)平均分配的橫向圖標(biāo)文字 new Row( crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ _getBottomItem(Icons.star, "1000"),
_getBottomItem(Icons.link,"1000"), _getBottomItem(Icons.subject, "1000"), ],
), ], ), ))), ); }
Flutter 中,你的布局很多時(shí)候就是這么一層一層嵌套出來(lái)的,當(dāng)然還有其他更高級(jí)的布局方式,這里就先不展開(kāi)了。5、Flutter 頁(yè)面
Flutter 中除了布局的 Widget,還有交互顯示的 Widget 和完整頁(yè)面呈現(xiàn)的Widget。其中常見(jiàn)的有
MaterialApp、Scaffold、Appbar、Text、Image、FlatButton等。下面簡(jiǎn)單介紹這些 Wdiget,并完成一個(gè)頁(yè)面。
類(lèi)型 作用特點(diǎn)
MaterialApp 一般作為APP頂層的主頁(yè)入口,可配置主題,多語(yǔ)言,路由等
Scaffold 一般用戶(hù)頁(yè)面的承載Widget,包含appbar、snackbar、drawer等material design的設(shè)定。
Appbar 一般用于Scaffold的appbar ,內(nèi)有標(biāo)題,二級(jí)頁(yè)面返回按鍵等,當(dāng)然不止這些,tabbar等也會(huì)需要它 。
Text 顯示文本,幾乎都會(huì)用到,主要是通過(guò)style設(shè)置TextStyle來(lái)設(shè)置字體樣式等。
RichText 富文本,通過(guò)設(shè)置TextSpan,可以拼接出富文本場(chǎng)景。
TextField 文本輸入框 :new TextField(controller: //文本控制器, obscureText: "hint文本");
Image 圖片加載:?new FadeInImage.assetNetwork( placeholder: "預(yù)覽圖", fit:
BoxFit.fitWidth, image: "url");
FlatButton 按鍵點(diǎn)擊:?new FlatButton(onPressed: () {},child: new Container());
那么再次直插主題實(shí)現(xiàn)一個(gè)簡(jiǎn)單完整的頁(yè)面試試。如下方代碼:
?●??首先我們創(chuàng)建一個(gè)StatefulWidget:DemoPage。
?●??然后在 _DemoPageState中,通過(guò)build創(chuàng)建了一個(gè)Scaffold。
?●??Scaffold內(nèi)包含了一個(gè)AppBar和一個(gè)ListView。
?●??AppBar類(lèi)似標(biāo)題了區(qū)域,其中設(shè)置了?title為 Text Widget。
?●??body是ListView,返回了20個(gè)之前我們創(chuàng)建過(guò)的 DemoItem Widget。
import 'package:flutter/material.dart'; import
'package:gsy_github_app_flutter/test/DemoItem.dart';
class DemoPage extends StatefulWidget { @override _DemoPageState createState()
=> _DemoPageState(); }
class _DemoPageState extends State<DemoPage> { @override Widget build
(BuildContext context) { ///一個(gè)頁(yè)面的開(kāi)始 ///如果是新頁(yè)面,會(huì)自帶返回按鍵 return new Scaffold(
///背景樣式 backgroundColor: Colors.blue, ///標(biāo)題欄,當(dāng)然不僅僅是標(biāo)題欄 appBar: new AppBar(
///這個(gè)title是一個(gè)Widget title: new Text("Title"), ), ///正式的頁(yè)面開(kāi)始
///一個(gè)ListView,20個(gè)Item body: new ListView.builder( itemBuilder: (context,
index) { return new DemoItem(); }, itemCount: 20, ), ); } }
最后我們創(chuàng)建一個(gè)StatelessWidget作為入口文件,實(shí)現(xiàn)一個(gè)MaterialApp將上方的DemoPage設(shè)置為home頁(yè)面,通過(guò)main
入口執(zhí)行頁(yè)面。
import 'package:flutter/material.dart'; import
'package:gsy_github_app_flutter/test/DemoPage.dart';
void main() { runApp(new DemoApp()); }
class DemoApp extends StatelessWidget { DemoApp({Key key}) : super(key: key);
@override Widget build(BuildContext context) { return new MaterialApp(home:
DemoPage()); } }
好吧,第一部分終于完了,這里主要講解都是一些簡(jiǎn)單基礎(chǔ)的東西,適合安利入坑。!( ̄^ ̄)ゞ
原文發(fā)布時(shí)間為:2018-10-9
本文作者:戀貓?jiān)铝?br>
本文來(lái)自云棲社區(qū)合作伙伴“安卓巴士Android開(kāi)發(fā)者門(mén)戶(hù)
<https://yq.aliyun.com/go/articleRenderRedirect?url=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzA3MjgwNDIzNQ%3D%3D%26amp%3Bmid%3D2651943682%26amp%3Bidx%3D1%26amp%3Bsn%3D4e4658a813f2cb20d7eeff86df864c73%26amp%3Bchksm%3D84fd61e6b38ae8f084ce0da0a89126a52c79a387d1333dd96e338bc6fd32d13195344e62677e%26amp%3Bscene%3D0%23rd>
”,了解相關(guān)信息可以關(guān)注“安卓巴士Android開(kāi)發(fā)者門(mén)戶(hù)
<https://yq.aliyun.com/go/articleRenderRedirect?url=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzA3MjgwNDIzNQ%3D%3D%26amp%3Bmid%3D2651943682%26amp%3Bidx%3D1%26amp%3Bsn%3D4e4658a813f2cb20d7eeff86df864c73%26amp%3Bchksm%3D84fd61e6b38ae8f084ce0da0a89126a52c79a387d1333dd96e338bc6fd32d13195344e62677e%26amp%3Bscene%3D0%23rd>
”。
熱門(mén)工具 換一換
