背景
在原生flutter混合開(kāi)發(fā)項(xiàng)目第一次提測(cè)階段局嘁,發(fā)現(xiàn)使用Charles
原生端抓包正常,flutter模塊卻無(wú)法抓包悦昵。通過(guò)查閱文章發(fā)現(xiàn)flutter使用Dio
庫(kù)進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),默認(rèn)情況下是不走手機(jī)代理的寡痰,想要抓包需要通過(guò)代碼去配置代理en~~~~~~
實(shí)現(xiàn)方案
本來(lái)想到兩種方案:
第一種:在flutter端通過(guò)彈框輸入IP和端口號(hào)棋凳,這樣可以省去iOS和Android兩端的處理,但是抓包時(shí)剩岳,既需要給手機(jī)配置代理拍棕,又需要在APP上輸入代理,對(duì)測(cè)試人員來(lái)說(shuō)绰播,操作太過(guò)麻煩。
第二種:APP啟動(dòng)時(shí)蠢箩,在原生端直接獲取手機(jī)代理事甜,通過(guò)channel
調(diào)用flutter方法保存代理滔韵,在Dio初始化時(shí)進(jìn)行設(shè)置。優(yōu)點(diǎn)是省去測(cè)試人員二次輸入過(guò)程,原生和flutter抓包保持一致囱皿,缺點(diǎn)忱嘹,兩端都需要獲取代理。
所以拘悦,果斷選擇第二種,畢竟用戶至上础米,兩端處理也只是一次性操作??~~~~
實(shí)踐過(guò)程
1.原生端獲取手機(jī)代理
// iOS獲取手機(jī)代理
- (void)syncProxy{
//自動(dòng)獲取手機(jī)代理
NSString * portalBaseUrlStr = @"http://www.baidu.com";
NSDictionary *proxySettings = (__bridge NSDictionary *)(CFNetworkCopySystemProxySettings());
NSArray *proxies = (__bridge NSArray *)(CFNetworkCopyProxiesForURL((__bridge CFURLRef _Nonnull)([NSURL URLWithString:portalBaseUrlStr]), (__bridge CFDictionaryRef _Nonnull)(proxySettings)));
NSDictionary *settings = [proxies firstObject];
NSString *hostName = [NSString stringWithFormat:@"%@",settings[@"kCFProxyHostNameKey"]];
NSString *portName = [NSString stringWithFormat:@"%@",settings[@"kCFProxyPortNumberKey"]];
//獲取為空時(shí)居然是字符串"(null)"
if ([hostName isEqualToString:@"(null)"]) {
hostName = @"";
}
if ([portName isEqualToString:@"(null)"]) {
portName = @"";
}
//第二步:調(diào)用flutter方法將IP和端口傳入 自己寫(xiě)??
}
portalBaseUrlStr
變量需要有值才能拿到IP和Port屁桑。方法調(diào)用可以放在APP啟動(dòng)時(shí),flutter初始化完成后靖秩,通過(guò)條件編譯只在DEBUG時(shí)調(diào)用即可~
2.flutter保存代理信息
///保存代理
void saveProxy(Map<String, dynamic> setting) async {
String host = setting['host'] ?? '';
String port = setting['port'] ?? '';
String proxy = '';
if (host.isNotEmpty && port.isNotEmpty) {
proxy = 'PROXY ' + host + ':' + port;
}
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('proxy', proxy);
}
將從原生端接收到的代理信息保存在本地
3.Dio設(shè)置代理
///設(shè)置代理
void setupProxy() async {
Dio dio = Dio();
SharedPreferences prefs = await SharedPreferences.getInstance();
String proxyStr = prefs.getString('proxy');
if (proxyStr != null && proxyStr.isNotEmpty) {
(dio.httpClientAdapter as DefaultHttpClientAdapter)
.onHttpClientCreate = (client) {
client.findProxy = (uri) {
return proxyStr;
};
//忽略證書(shū)
client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
};
}
}
dio可通過(guò)懶加載方式進(jìn)行創(chuàng)建竖瘾,在dio對(duì)象初始化完成后,獲取本地保存的代理信息進(jìn)行設(shè)置即可惠拭。這里做了條件判斷庸论,如果沒(méi)有代理信息,則不進(jìn)行配置葡公。APP啟動(dòng)時(shí)會(huì)重置代理信息,所以無(wú)需擔(dān)心緩存代理的清理問(wèn)題涵亏。
結(jié)語(yǔ)
本文是對(duì)在flutter抓包實(shí)踐的一次學(xué)習(xí)和總結(jié),分享出來(lái)希望大家都能有所收獲??~