Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DiDi
DoraemonKit
提交
be415998
D
DoraemonKit
项目概览
DiDi
/
DoraemonKit
12 个月 前同步成功
通知
166
Star
19623
Fork
3062
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
DoraemonKit
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
be415998
编写于
2月 24, 2021
作者:
L
linusflow
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of
https://github.com/didi/DoraemonKit
上级
69eeed5b
13e1b924
变更
33
隐藏空白更改
内联
并排
Showing
33 changed file
with
415 addition
and
284 deletion
+415
-284
Doc/iOS-ReleaseNotes.md
Doc/iOS-ReleaseNotes.md
+5
-2
DoraemonKit.podspec
DoraemonKit.podspec
+1
-1
Flutter/CHANGELOG.md
Flutter/CHANGELOG.md
+3
-1
Flutter/README.md
Flutter/README.md
+1
-0
Flutter/example/ios/Flutter/.last_build_id
Flutter/example/ios/Flutter/.last_build_id
+1
-1
Flutter/example/ios/Podfile.lock
Flutter/example/ios/Podfile.lock
+12
-0
Flutter/example/lib/main.dart
Flutter/example/lib/main.dart
+52
-34
Flutter/example/pubspec.yaml
Flutter/example/pubspec.yaml
+4
-0
Flutter/lib/dokit.dart
Flutter/lib/dokit.dart
+2
-1
Flutter/lib/engine/dokit_binding.dart
Flutter/lib/engine/dokit_binding.dart
+12
-1
Flutter/lib/engine/dokit_http.dart
Flutter/lib/engine/dokit_http.dart
+26
-25
Flutter/lib/ui/resident_page.dart
Flutter/lib/ui/resident_page.dart
+12
-25
Flutter/pubspec.lock
Flutter/pubspec.lock
+33
-68
Flutter/pubspec.yaml
Flutter/pubspec.yaml
+1
-1
README.md
README.md
+5
-4
Web/README.md
Web/README.md
+64
-0
iOS/DoraemonKit/Src/Core/Manager/DoraemonManager.h
iOS/DoraemonKit/Src/Core/Manager/DoraemonManager.h
+6
-1
iOS/DoraemonKit/Src/Core/Manager/DoraemonManager.m
iOS/DoraemonKit/Src/Core/Manager/DoraemonManager.m
+5
-0
iOS/DoraemonKit/Src/Core/Network/Interceptor/DoraemonNSURLProtocol.m
...nKit/Src/Core/Network/Interceptor/DoraemonNSURLProtocol.m
+8
-3
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/DoraemonNetFlowHttpModel.h
...n/Performance/NetFlow/Function/DoraemonNetFlowHttpModel.h
+1
-1
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/DoraemonNetFlowHttpModel.m
...n/Performance/NetFlow/Function/DoraemonNetFlowHttpModel.m
+8
-13
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/DoraemonNetFlowManager.h
...gin/Performance/NetFlow/Function/DoraemonNetFlowManager.h
+4
-0
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/DoraemonNetFlowManager.m
...gin/Performance/NetFlow/Function/DoraemonNetFlowManager.m
+74
-13
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/Util/DoraemonUrlUtil.h
...lugin/Performance/NetFlow/Function/Util/DoraemonUrlUtil.h
+3
-3
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/Util/DoraemonUrlUtil.m
...lugin/Performance/NetFlow/Function/Util/DoraemonUrlUtil.m
+11
-30
iOS/DoraemonKit/Src/Core/Plugin/Performance/WeakNetwork/Function/DoraemonWeakNetworkManager.m
...ormance/WeakNetwork/Function/DoraemonWeakNetworkManager.m
+3
-1
iOS/DoraemonKit/Src/Core/Plugin/Platform/Mock/Function/DoraemonMockManager.m
.../Core/Plugin/Platform/Mock/Function/DoraemonMockManager.m
+8
-5
iOS/DoraemonKitDemo/DoraemonKitDemo/DemoVC/Net/ NSURLProtocol/DoraemonDemoURLProtocol1.m
...Demo/DemoVC/Net/ NSURLProtocol/DoraemonDemoURLProtocol1.m
+6
-4
iOS/DoraemonKitDemo/DoraemonKitDemo/DemoVC/Net/ NSURLProtocol/DoraemonDemoURLProtocol2.m
...Demo/DemoVC/Net/ NSURLProtocol/DoraemonDemoURLProtocol2.m
+6
-4
iOS/DoraemonKitDemo/DoraemonKitDemo/DemoVC/Net/DoraemonDemoNetViewController.m
...oraemonKitDemo/DemoVC/Net/DoraemonDemoNetViewController.m
+6
-5
iOS/DoraemonKitDemo/DoraemonKitDemo/DemoVC/Performance/DoraemonDemoPerformanceViewController.m
...emoVC/Performance/DoraemonDemoPerformanceViewController.m
+4
-3
iOS/DoraemonKitDemo/Podfile
iOS/DoraemonKitDemo/Podfile
+1
-1
iOS/DoraemonKitDemo/Podfile.lock
iOS/DoraemonKitDemo/Podfile.lock
+27
-33
未找到文件。
Doc/iOS-ReleaseNotes.md
浏览文件 @
be415998
# Release Notes
### 3.0.7
1、DoKit iOS github issues bug fixed
### 3.0.4
1、DoKit iOS端文件同步助手正式上线
### 3.0.2
1、支持每一个内置Kit,进行位置重排,添加删除某一个Kit
...
...
@@ -242,4 +245,4 @@
3、性能工具:帧率、CPU、内存、流量、自定义
4、视觉工具:颜色吸管、组件检查、对齐标尺
\ No newline at end of file
4、视觉工具:颜色吸管、组件检查、对齐标尺
DoraemonKit.podspec
浏览文件 @
be415998
...
...
@@ -7,7 +7,7 @@
Pod
::
Spec
.
new
do
|
s
|
s
.
name
=
'DoraemonKit'
s
.
version
=
'3.0.
6
'
s
.
version
=
'3.0.
7
'
s
.
summary
=
'iOS各式各样的工具集合'
s
.
description
=
<<-
DESC
iOS各式各样的工具集合 Desc
...
...
Flutter/CHANGELOG.md
浏览文件 @
be415998
## [0.2.14] - methodchannel增加黑名单过滤
## [0.2.13] - 修复网络监控会影响非文本请求内容响应的问题
## [0.2.12] - 修改页面层级,现在DoKitApp将以Stack存放用户传入的Widget,防止各种InheritedWidget影响到用户Widget
## [0.2.11] - 修复一些UI异常问题;日志模块增加错误信息过滤,防止被错误日志冲刷掉;
## [0.2.10] - 修复DoKitApp
再
某些case下获取高度为0的异常.
## [0.2.10] - 修复DoKitApp
在
某些case下获取高度为0的异常.
## [0.2.9] - 修改DoKitApp类型,自定义Overlay容器防止各种InheritedWidget使用异常.
## [0.2.8] - 修复网络请求返回结果乱码问题;增加method—channel耗时统计;日志/方法通道/网络请求增加清空按钮.
## [0.2.7] - 网络请求增加RequestHeaders信息展示,增加非文本类型的返回结果size展示.
...
...
Flutter/README.md
浏览文件 @
be415998
...
...
@@ -64,6 +64,7 @@ appCreator | DoKitAppCreator | 异步返回根布局 | 同上
useInRelease | bool |是否在release模式下显示DoKit | x
logCallback | LogCallback | 调用print方法打印日志时被回调 | x
exceptionCallback | ExceptionCallback | 异常回调 | x
methodChannelBlackList | List
<String>
| 过滤方法通道的黑名单 | x
releaseAction | Function | release模式下执行该函数,该值为空则会直接调用系统的runApp |x
...
...
Flutter/example/ios/Flutter/.last_build_id
浏览文件 @
be415998
310a81ea87d5214a76b45c32814582e1
\ No newline at end of file
d4d880dcbf7794a0d22fc1a36580d2b3
\ No newline at end of file
Flutter/example/ios/Podfile.lock
浏览文件 @
be415998
...
...
@@ -2,10 +2,14 @@ PODS:
- Flutter (1.0.0)
- package_info (0.0.1):
- Flutter
- path_provider (0.0.1):
- Flutter
- path_provider_linux (0.0.1):
- Flutter
- path_provider_windows (0.0.1):
- Flutter
- sensors (0.0.1):
- Flutter
- shared_preferences (0.0.1):
- Flutter
- shared_preferences_linux (0.0.1):
...
...
@@ -20,8 +24,10 @@ PODS:
DEPENDENCIES:
- Flutter (from `Flutter`)
- package_info (from `.symlinks/plugins/package_info/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
- path_provider_windows (from `.symlinks/plugins/path_provider_windows/ios`)
- sensors (from `.symlinks/plugins/sensors/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`)
- shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`)
...
...
@@ -33,10 +39,14 @@ EXTERNAL SOURCES:
:path: Flutter
package_info:
:path: ".symlinks/plugins/package_info/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
path_provider_linux:
:path: ".symlinks/plugins/path_provider_linux/ios"
path_provider_windows:
:path: ".symlinks/plugins/path_provider_windows/ios"
sensors:
:path: ".symlinks/plugins/sensors/ios"
shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios"
shared_preferences_linux:
...
...
@@ -51,8 +61,10 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d
path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4
path_provider_windows: a2b81600c677ac1959367280991971cb9a1edb3b
sensors: 84eb7a30e47a649e4172b71d6e81be614c280336
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78
shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087
...
...
Flutter/example/lib/main.dart
浏览文件 @
be415998
...
...
@@ -10,17 +10,26 @@ import 'dart:convert';
import
'dart:io'
;
import
'dart:typed_data'
;
import
'package:dio/dio.dart'
;
import
'package:flutter/material.dart'
;
import
'package:dokit/dokit.dart'
;
import
'package:flutter/services.dart'
;
import
'package:path_provider/path_provider.dart'
;
void
main
(
)
{
List
<
String
>
blackList
=
[
'plugins.flutter.io/sensors/gyroscope'
,
'plugins.flutter.io/sensors/user_accel'
,
'plugins.flutter.io/sensors/accelerometer'
];
DoKit
.
runApp
(
app:
DoKitApp
(
MyApp
()),
useInRelease:
true
,
logCallback:
(
log
)
{
String
i
=
log
;
},
methodChannelBlackList:
blackList
,
exceptionCallback:
(
obj
,
trace
)
{
print
(
'ttt
$obj
'
);
});
...
...
@@ -117,6 +126,20 @@ class _DoKitTestPageState extends State<DoKitTestPage> {
onPressed:
mockHttpGet
,
),
),
Container
(
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
4
)),
color:
Color
(
0xffcccccc
)),
margin:
EdgeInsets
.
only
(
bottom:
30
),
child:
FlatButton
(
child:
Text
(
'Test Download'
,
style:
TextStyle
(
color:
Color
(
0xff000000
),
fontSize:
18
,
)),
onPressed:
testDownload
,
),
),
Container
(
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
4
)),
...
...
@@ -178,40 +201,35 @@ class _DoKitTestPageState extends State<DoKitTestPage> {
Timer
timer
;
// downloadFile(String url, {String filename}) async {
// var httpClient = http.Client();
// var request = new http.Request('GET', Uri.parse(url));
// var response = httpClient.send(request);
// String dir = '/test/';
//
// List<List<int>> chunks = new List();
// int downloaded = 0;
//
// response.asStream().listen((http.StreamedResponse r) {
//
// r.stream.listen((List<int> chunk) {
// // Display percentage of completion
// debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
//
// chunks.add(chunk);
// downloaded += chunk.length;
// }, onDone: () async {
// // Display percentage of completion
// debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
//
// // Save the file
// // File file = new File('$dir/$filename');
// // final Uint8List bytes = Uint8List(r.contentLength);
// // int offset = 0;
// // for (List<int> chunk in chunks) {
// // bytes.setRange(offset, offset + chunk.length, chunk);
// // offset += chunk.length;
// // }
// // await file.writeAsBytes(bytes);
// return;
// });
// });
// }
testDownload
()
async
{
String
url
=
'https://pt-starfile.didistatic.com/static/starfile/node20210220/895f1e95e30aba5dd56d6f2ccf768b57/GjzGU0Pvv11613804530384.zip'
;
String
savePath
=
await
getPhoneLocalPath
();
String
zipName
=
'test.zip'
;
Dio
dio
=
new
Dio
();
print
(
"
$savePath
/
$zipName
"
);
Response
response
=
await
dio
.
download
(
url
,
"
$savePath
/
$zipName
"
,
onReceiveProgress:
(
received
,
total
)
{
if
(
total
!=
-
1
)
{
// 当前下载的百分比
// print((received / total * 100).toStringAsFixed(0) + "%");
// print("received=$received total=$total");
if
(
received
==
total
)
{
print
(
"下载完成 ✅ "
);
}
}
else
{}
});
}
///获取手机的存储目录路径
///getExternalStorageDirectory() 获取的是 android 的外部存储 (External Storage)
/// getApplicationDocumentsDirectory 获取的是 ios 的Documents` or `Downloads` 目录
Future
<
String
>
getPhoneLocalPath
()
async
{
final
directory
=
Theme
.
of
(
context
).
platform
==
TargetPlatform
.
android
?
await
getExternalStorageDirectory
()
:
await
getApplicationDocumentsDirectory
();
return
directory
.
path
;
}
void
testMethodChannel
()
{
timer
?.
cancel
();
...
...
Flutter/example/pubspec.yaml
浏览文件 @
be415998
...
...
@@ -11,6 +11,10 @@ dependencies:
sdk
:
flutter
dokit
:
path
:
..
dio
:
3.0.10
path_provider
:
1.6.0
dev_dependencies
:
flutter_test
:
sdk
:
flutter
...
...
Flutter/lib/dokit.dart
浏览文件 @
be415998
...
...
@@ -5,7 +5,6 @@ import 'package:dokit/ui/dokit_btn.dart';
import
'package:dokit/ui/dokit_app.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'dart:core'
;
import
'package:flutter/widgets.dart'
as
dart
;
import
'package:dokit/kit/kit_page.dart'
;
...
...
@@ -38,6 +37,7 @@ class DoKit {
bool
useInRelease
=
false
,
LogCallback
logCallback
,
ExceptionCallback
exceptionCallback
,
List
<
String
>
methodChannelBlackList
=
const
[],
Function
releaseAction
})
async
{
assert
(
app
!=
null
||
appCreator
!=
null
,
'app and appCreator are both null'
);
...
...
@@ -53,6 +53,7 @@ class DoKit {
}
return
;
}
blackList
=
methodChannelBlackList
;
runZoned
(
()
async
=>
{
_ensureDoKitBinding
(
useInRelease:
useInRelease
),
...
...
Flutter/lib/engine/dokit_binding.dart
浏览文件 @
be415998
...
...
@@ -7,6 +7,8 @@ import 'package:flutter/foundation.dart';
import
'package:flutter/services.dart'
;
import
'package:flutter/widgets.dart'
;
List
<
String
>
blackList
=
[];
class
DoKitWidgetsFlutterBinding
extends
WidgetsFlutterBinding
with
DoKitServicesBinding
{
static
WidgetsBinding
ensureInitialized
()
{
...
...
@@ -43,6 +45,9 @@ class DoKitBinaryMessenger extends BinaryMessenger {
@override
Future
<
void
>
handlePlatformMessage
(
String
channel
,
ByteData
data
,
callback
)
{
ChannelInfo
info
=
saveMessage
(
channel
,
data
,
false
);
if
(
info
==
null
)
{
return
origin
.
handlePlatformMessage
(
channel
,
data
,
callback
);
}
PlatformMessageResponseCallback
wrapper
=
(
ByteData
data
)
{
resolveResult
(
info
,
data
);
callback
(
data
);
...
...
@@ -53,6 +58,9 @@ class DoKitBinaryMessenger extends BinaryMessenger {
@override
Future
<
ByteData
>
send
(
String
channel
,
ByteData
message
)
async
{
ChannelInfo
info
=
saveMessage
(
channel
,
message
,
true
);
if
(
info
==
null
)
{
return
origin
.
send
(
channel
,
message
);
}
ByteData
result
=
await
origin
.
send
(
channel
,
message
);
resolveResult
(
info
,
result
);
return
result
;
...
...
@@ -67,7 +75,7 @@ class DoKitBinaryMessenger extends BinaryMessenger {
}
else
if
(
info
.
messageCodec
!=
null
)
{
info
.
results
=
info
.
messageCodec
.
decodeMessage
(
result
);
info
.
endTimestamp
=
new
DateTime
.
now
().
millisecondsSinceEpoch
;
}
else
{
}
else
{
info
.
endTimestamp
=
new
DateTime
.
now
().
millisecondsSinceEpoch
;
}
}
...
...
@@ -82,6 +90,9 @@ class DoKitBinaryMessenger extends BinaryMessenger {
if
(
kit
==
null
)
{
return
null
;
}
if
(
blackList
!=
null
&&
blackList
.
contains
(
name
))
{
return
null
;
}
ChannelInfo
info
;
try
{
info
=
filterSystemChannel
(
name
,
data
,
send
);
...
...
Flutter/lib/engine/dokit_http.dart
浏览文件 @
be415998
...
...
@@ -497,20 +497,21 @@ class DoKitHttpClientResponse implements HttpClientResponse {
@override
StreamSubscription
<
List
<
int
>>
listen
(
void
Function
(
List
<
int
>
event
)
onData
,
{
Function
onError
,
void
Function
()
onDone
,
bool
cancelOnError
})
{
if
(!
isTextResponse
())
{
recordResponse
(
statusCode
,
"返回结果不支持解析"
,
headers
?.
toString
(),
contentLength
);
return
origin
.
listen
(
onData
,
onError:
onError
,
onDone:
onDone
,
cancelOnError:
cancelOnError
);
}
void
onDataWrapper
(
List
<
int
>
result
)
{
onData
(
result
);
try
{
if
(
isTextResponse
())
{
if
(
getEncoding
()
!=
null
)
{
recordResponse
(
statusCode
,
getEncoding
().
decode
(
result
),
headers
?.
toString
(),
contentLength
);
}
else
{
recordResponse
(
statusCode
,
"返回结果解析失败"
,
headers
?.
toString
(),
contentLength
);
}
if
(
getEncoding
()
!=
null
)
{
recordResponse
(
statusCode
,
getEncoding
().
decode
(
result
),
headers
?.
toString
(),
contentLength
);
}
else
{
recordResponse
(
statusCode
,
"返回结果
不支持解析
"
,
headers
?.
toString
(),
contentLength
);
statusCode
,
"返回结果
解析失败
"
,
headers
?.
toString
(),
contentLength
);
}
}
catch
(
e
)
{
recordResponse
(
...
...
@@ -604,27 +605,27 @@ class DoKitHttpClientResponse implements HttpClientResponse {
@override
Stream
<
S
>
transform
<
S
>(
StreamTransformer
<
List
<
int
>,
S
>
streamTransformer
)
{
Stream
s
=
origin
.
transform
(
streamTransformer
);
if
(!
isTextResponse
())
{
recordResponse
(
statusCode
,
"返回结果不支持解析"
,
headers
?.
toString
(),
contentLength
);
return
s
;
}
s
=
s
.
asBroadcastStream
();
s
.
listen
((
event
)
{
if
(
isTextResponse
())
{
if
(
event
is
Uint8List
)
{
Uint8List
result
=
event
;
if
(
getEncoding
()
!=
null
)
{
recordResponse
(
statusCode
,
getEncoding
().
decode
(
result
.
toList
()),
headers
?.
toString
(),
event
.
length
);
}
else
{
recordResponse
(
statusCode
,
"返回结果解析失败"
,
headers
?.
toString
(),
contentLength
);
}
}
else
if
(
event
is
String
)
{
recordResponse
(
statusCode
,
event
,
headers
?.
toString
(),
contentLength
);
if
(
event
is
Uint8List
)
{
Uint8List
result
=
event
;
if
(
getEncoding
()
!=
null
)
{
recordResponse
(
statusCode
,
getEncoding
().
decode
(
result
.
toList
()),
headers
?.
toString
(),
event
.
length
);
}
else
{
recordResponse
(
statusCode
,
'unknown type:
${event.runtimeType}
'
,
headers
?.
toString
(),
contentLength
);
recordResponse
(
statusCode
,
"返回结果解析失败"
,
headers
?.
toString
(),
contentLength
);
}
}
else
if
(
event
is
String
)
{
recordResponse
(
statusCode
,
event
,
headers
?.
toString
(),
contentLength
);
}
else
{
recordResponse
(
statusCode
,
"返回结果不支持解析"
,
headers
?.
toString
(),
contentLength
);
recordResponse
(
statusCode
,
'unknown type:
${event.runtimeType}
'
,
headers
?.
toString
(),
contentLength
);
}
});
return
s
;
...
...
Flutter/lib/ui/resident_page.dart
浏览文件 @
be415998
...
...
@@ -18,34 +18,21 @@ class ResidentPage extends StatefulWidget {
class
ResidentPageState
extends
State
<
ResidentPage
>
{
Widget
getPage
()
{
if
(
ResidentPage
.
tag
==
KitPageManager
.
KIT_ALL
)
{
return
KitPage
();
}
if
(
ApmKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)
!=
null
)
{
return
ApmKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)
.
createDisplayPage
();
}
if
(
CommonKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)
!=
null
)
{
return
CommonKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)
.
createDisplayPage
();
}
return
Container
(
alignment:
Alignment
.
center
,
child:
Text
(
'无数据'
,
style:
TextStyle
(
color:
Color
(
0xff999999
),
fontSize:
20
)),
);
Widget
page
;
page
??=
ApmKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)?.
createDisplayPage
();
page
??=
CommonKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)?.
createDisplayPage
();
page
??=
KitPage
();
return
page
;
}
String
getTitle
()
{
if
(
ApmKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)
!=
null
)
{
return
ApmKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
).
getKitName
();
}
if
(
CommonKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)
!=
null
)
{
return
CommonKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
).
getKitName
();
}
return
'DoKit'
;
String
title
;
title
??=
ApmKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)?.
getKitName
();
title
??=
CommonKitManager
.
instance
.
getKit
(
ResidentPage
.
tag
)?.
getKitName
();
title
??=
'DoKit'
;
return
title
;
}
_tapListener
(
String
current
)
{
...
...
Flutter/pubspec.lock
浏览文件 @
be415998
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.13"
args:
dependency: transitive
description:
name: args
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.6.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.
4
.1"
version: "2.
5.0-nullsafety
.1"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.
0.0
"
char
code
:
version: "2.
1.0-nullsafety.1
"
char
acters
:
dependency: transitive
description:
name: char
code
name: char
acters
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.3"
c
ollection
:
version: "1.1.
0-nullsafety.
3"
c
harcode
:
dependency: transitive
description:
name: c
ollection
name: c
harcode
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.
14.12
"
c
onvert
:
version: "1.
2.0-nullsafety.1
"
c
lock
:
dependency: transitive
description:
name: c
onvert
name: c
lock
url: "https://pub.flutter-io.cn"
source: hosted
version: "
2.1
.1"
c
rypto
:
version: "
1.1.0-nullsafety
.1"
c
ollection
:
dependency: transitive
description:
name: c
rypto
name: c
ollection
url: "https://pub.flutter-io.cn"
source: hosted
version: "
2.1.4
"
version: "
1.15.0-nullsafety.3
"
date_format:
dependency: "direct main"
description:
...
...
@@ -64,6 +50,13 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.9"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0-nullsafety.1"
ffi:
dependency: transitive
description:
...
...
@@ -93,13 +86,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.12"
intl:
dependency: transitive
description:
...
...
@@ -113,14 +99,14 @@ packages:
name: matcher
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.12.
6
"
version: "0.12.
10-nullsafety.1
"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.
1.8
"
version: "1.
3.0-nullsafety.3
"
package_info:
dependency: "direct main"
description:
...
...
@@ -134,7 +120,7 @@ packages:
name: path
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.
6.4
"
version: "1.
8.0-nullsafety.1
"
path_provider_linux:
dependency: transitive
description:
...
...
@@ -156,13 +142,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.4+3"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.0"
platform:
dependency: transitive
description:
...
...
@@ -184,13 +163,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.13"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.3"
shared_preferences:
dependency: "direct main"
description:
...
...
@@ -244,56 +216,56 @@ packages:
name: source_span
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.
7.0
"
version: "1.
8.0-nullsafety.2
"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.
9.3
"
version: "1.
10.0-nullsafety.1
"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.
0.0
"
version: "2.
1.0-nullsafety.1
"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.
0.5
"
version: "1.
1.0-nullsafety.1
"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.
1.0
"
version: "1.
2.0-nullsafety.1
"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.1
5
"
version: "0.2.1
9-nullsafety.2
"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.
1.6
"
version: "1.
3.0-nullsafety.3
"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.
0.8
"
version: "2.
1.0-nullsafety.3
"
vm_service:
dependency: "direct main"
description:
...
...
@@ -315,13 +287,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.6.1"
sdks:
dart: ">=2.
7.0 <3.0
.0"
dart: ">=2.
10.0-110 <2.11
.0"
flutter: ">=1.17.0 <2.0.0"
Flutter/pubspec.yaml
浏览文件 @
be415998
name
:
dokit
description
:
开发工具集
version
:
0.2.1
2
version
:
0.2.1
4
homepage
:
https://www.dokit.cn/#/index/home
...
...
README.md
浏览文件 @
be415998
...
...
@@ -27,8 +27,8 @@
<img
src=
"https://javer.oss-cn-shanghai.aliyuncs.com/doraemon/github/DoraemonKit_github.png"
width =
"150"
height =
"150"
alt=
"DoraemonKit"
align=
left
/>
<img
src=
"https://img.shields.io/github/license/didi/DoraemonKit.svg"
align=
left
/>
<img
src=
"https://img.shields.io/badge/Android-3.3.5-blue.svg"
align=
left
/>
<img
src=
"https://img.shields.io/badge/iOS-3.0.
4
-yellow.svg"
align=
left
/>
<img
src=
"https://img.shields.io/badge/Flutter-0.2.1
2
-blue.svg"
align=
left
/>
<img
src=
"https://img.shields.io/badge/iOS-3.0.
7
-yellow.svg"
align=
left
/>
<img
src=
"https://img.shields.io/badge/Flutter-0.2.1
4
-blue.svg"
align=
left
/>
<img
src=
"https://img.shields.io/badge/miniapp-0.0.1-red.svg"
align=
left
/>
<img
src=
"https://img.shields.io/badge/PRs-welcome-brightgreen.svg"
align=
left
/>
</div>
...
...
@@ -238,7 +238,7 @@ tips : 如果使用我们滴滴优秀的开源跨端方案 [chameleon](https:/
[
yixiangboy
](
https://github.com/yixiangboy
)
、
[
jtsky
](
https://github.com/jtsky
)
、
[
LinJZong
](
https://github.com/LinJZong
)
、
[
ydlsl
](
https://github.com/ydlsl
)
、
[
changzuozhen
](
https://github.com/changzuozhen
)
、
[
jayconscious
](
https://github.com/jayconscious
)
**贡献者榜单**
...
...
@@ -270,7 +270,8 @@ tips : 如果使用我们滴滴优秀的开源跨端方案 [chameleon](https:/
[
sagdragon
](
https://github.com/sagdragon
)
、
[
ccworld1000
](
https://github.com/ccworld1000
)
、
[
HDB-Li
](
https://github.com/HDB-Li
)
、
[
yu-jianfeng
](
https://github.com/yu-jianfeng
)
[
yu-jianfeng
](
https://github.com/yu-jianfeng
)
、
[
ydlsl
](
https://github.com/ydlsl
)
如何成为外部贡献者? 提交有意义的PR,并被采纳。
...
...
Web/README.md
0 → 100644
浏览文件 @
be415998
## 介绍
一款面向前端生态的开发工具
### 愿景
让前端开发更美好
### 功能
#### 日志
展示
`Console`
控制台的日志
##### 基础功能
-
支持所有的
`console`
方法
-
支持日志的筛选和清除
-
支持执行简易的
`javascript`
命令
##### 进阶功能
-
打通平台侧的日志查看,支持查看多个设备
#### 接口抓取
展示所有的数据请求
##### 基础功能
-
支持抓取常用的接口类型
`xhr`
和
`fetch`
-
展示请求的详细内容
-
展示响应的详细内容
##### 进阶功能
-
支持拦截请求,修改数据(平台端进行修改)
-
支持根据请求,快捷添加 Mock 接口 (和平台侧打通)
#### 视图元素查看
展示视图树,展示
`Dom`
树
##### 基础功能
-
展示整个页面的
`Dom`
树
-
支持展开、关闭、选择(高亮元素)
-
支持查看特定元素的内容
-
查看元素的样式
-
查看元素的盒模型
##### 进阶功能
-
支持切换模式查看元素
-
考虑移动端的交互,点击区域不宜过小
#### 资源查看
展示页面的所有资源请求
##### 基础功能
-
展示
`javascript`
资源
-
展示
`css`
资源
-
展示
`image`
等媒体资源
#### 应用存储
展示当前页面的存储信息
##### 基础功能
-
支持查看并修改
`LocalStorage`
-
支持查看并修改
`SessionStorage`
-
支持查看
`Cookie`
#### 接口Mock
无侵入式 Mock 数据
##### 基础功能
-
支持无侵入式一键 Mock
-
支持自动同步真实请求数据到平台侧,并与快速创建
#### 屏幕录制 & 回放
> 功能设计中
#### 自动化测试
> 功能设计中
iOS/DoraemonKit/Src/Core/Manager/DoraemonManager.h
浏览文件 @
be415998
...
...
@@ -113,12 +113,17 @@ typedef NS_ENUM(NSUInteger, DoraemonManagerPluginType) {
@property
(
nonatomic
,
copy
)
NSString
*
pId
;
//产品id 平台端的工具必须填写
@property
(
nonatomic
,
copy
)
NSString
*
mockDomain
;
//产品mockDomain 非必填 默认mock.dokit.cn
@property
(
nonatomic
,
assign
)
BOOL
autoDock
;
//dokit entry icon support autoDock,deffault yes
-
(
void
)
install
;
//带有平台端功能的s初始化方式
//
带有平台端功能的s初始化方式
-
(
void
)
installWithPid
:(
NSString
*
)
pId
;
// 自定义平台mockDomain初始化方式
-
(
void
)
installWithMockDomain
:(
NSString
*
)
mockDomain
;
// 定制起始位置 | 适用正好挡住关键位置
-
(
void
)
installWithStartingPosition
:(
CGPoint
)
position
;
...
...
iOS/DoraemonKit/Src/Core/Manager/DoraemonManager.m
浏览文件 @
be415998
...
...
@@ -110,6 +110,11 @@ typedef void (^DoraemonPerformanceBlock)(NSDictionary *);
[
self
install
];
}
-
(
void
)
installWithMockDomain
:(
NSString
*
)
mockDomain
{
self
.
mockDomain
=
mockDomain
;
[
self
install
];
}
-
(
void
)
installWithStartingPosition
:(
CGPoint
)
position
{
_startingPosition
=
position
;
[
self
installWithCustomBlock
:
^
{
...
...
iOS/DoraemonKit/Src/Core/Network/Interceptor/DoraemonNSURLProtocol.m
浏览文件 @
be415998
...
...
@@ -11,6 +11,7 @@
#import "DoraemonNetFlowManager.h"
#import "DoraemonURLSessionDemux.h"
#import "DoraemonNetworkInterceptor.h"
#import "DoraemonManager.h"
#import "DoraemonMockManager.h"
#import "DoraemonDefine.h"
#import "DoraemonUrlUtil.h"
...
...
@@ -78,8 +79,10 @@ static NSString * const kDoraemonProtocolKey = @"doraemon_protocol_key";
NSMutableURLRequest
*
mutableReqeust
=
[
request
mutableCopy
];
[
NSURLProtocol
setProperty
:
@YES
forKey
:
kDoraemonProtocolKey
inRequest
:
mutableReqeust
];
if
([[
DoraemonMockManager
sharedInstance
]
needMock
:
request
])
{
NSString
*
mockDomain
=
[
DoraemonManager
shareInstance
].
mockDomain
?
[
DoraemonManager
shareInstance
].
mockDomain
:
@"https://mock.dokit.cn/"
;
NSString
*
mockSceneUrl
=
[
mockDomain
stringByAppendingString
:
@"api/app/scene/%@"
];
NSString
*
sceneId
=
[[
DoraemonMockManager
sharedInstance
]
getSceneId
:
request
];
NSString
*
urlString
=
[
NSString
stringWithFormat
:
@"https://mock.dokit.cn/api/app/scene/%@"
,
sceneId
];
NSString
*
urlString
=
[
NSString
stringWithFormat
:
mockSceneUrl
,
sceneId
];
DoKitLog
(
@"MOCK URL == %@"
,
urlString
);
mutableReqeust
=
[
NSMutableURLRequest
requestWithURL
:[
NSURL
URLWithString
:
urlString
]];
dispatch_async
(
dispatch_get_main_queue
(),
^
{
...
...
@@ -98,8 +101,10 @@ static NSString * const kDoraemonProtocolKey = @"doraemon_protocol_key";
});
}
else
if
(
DoraemonWeakNetwork_WeakSpeed
==
[[
DoraemonNetworkInterceptor
shareInstance
].
weakDelegate
weakNetSelecte
]){
DoKitLog
(
@"yd WeakUpFlow Net"
);
[[
DoraemonNetworkInterceptor
shareInstance
].
weakDelegate
handleWeak
:[
DoraemonUrlUtil
getHttpBodyFromRequest
:
self
.
request
]
isDown
:
NO
];
[
self
.
task
resume
];
[[
DoraemonNetFlowManager
shareInstance
]
httpBodyFromRequest
:
self
.
request
bodyCallBack
:
^
(
NSData
*
body
)
{
[[
DoraemonNetworkInterceptor
shareInstance
].
weakDelegate
handleWeak
:
body
isDown
:
NO
];
[
self
.
task
resume
];
}];
}
else
{
[
self
.
task
resume
];
}
...
...
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/DoraemonNetFlowHttpModel.h
浏览文件 @
be415998
...
...
@@ -28,6 +28,6 @@
@property
(
nonatomic
,
copy
)
NSString
*
topVc
;
//流量触发时候的顶层vc
+
(
DoraemonNetFlowHttpModel
*
)
dealWithResponseData
:(
NSData
*
)
responseData
response
:(
NSURLResponse
*
)
response
request
:(
NSURLRequest
*
)
request
;
+
(
void
)
dealWithResponseData
:(
NSData
*
)
responseData
response
:(
NSURLResponse
*
)
response
request
:(
NSURLRequest
*
)
request
complete
:(
void
(
^
)(
DoraemonNetFlowHttpModel
*
model
))
complete
;
@end
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/DoraemonNetFlowHttpModel.m
浏览文件 @
be415998
...
...
@@ -6,24 +6,19 @@
//
#import "DoraemonNetFlowHttpModel.h"
#import "DoraemonNetFlowManager.h"
#import "NSURLRequest+Doraemon.h"
#import "DoraemonUrlUtil.h"
@implementation
DoraemonNetFlowHttpModel
+
(
DoraemonNetFlowHttpModel
*
)
dealWithResponseData
:(
NSData
*
)
responseData
response
:(
NSURLResponse
*
)
response
request
:(
NSURLRequest
*
)
request
{
+
(
void
)
dealWithResponseData
:(
NSData
*
)
responseData
response
:(
NSURLResponse
*
)
response
request
:(
NSURLRequest
*
)
request
complete
:(
void
(
^
)(
DoraemonNetFlowHttpModel
*
model
))
complete
{
DoraemonNetFlowHttpModel
*
httpModel
=
[[
DoraemonNetFlowHttpModel
alloc
]
init
];
//request
httpModel
.
request
=
request
;
httpModel
.
requestId
=
request
.
requestId
;
httpModel
.
url
=
[
request
.
URL
absoluteString
];
httpModel
.
method
=
request
.
HTTPMethod
;
NSData
*
httpBody
=
[
DoraemonUrlUtil
getHttpBodyFromRequest
:
request
];
httpModel
.
requestBody
=
[
DoraemonUrlUtil
convertJsonFromData
:
httpBody
];
httpModel
.
uploadFlow
=
[
NSString
stringWithFormat
:
@"%zi"
,[
DoraemonUrlUtil
getRequestLength
:
request
]];
//response
httpModel
.
mineType
=
response
.
MIMEType
;
httpModel
.
response
=
response
;
...
...
@@ -33,12 +28,12 @@
httpModel
.
responseBody
=
[
DoraemonUrlUtil
convertJsonFromData
:
responseData
];
httpModel
.
totalDuration
=
[
NSString
stringWithFormat
:
@"%fs"
,[[
NSDate
date
]
timeIntervalSince1970
]
-
request
.
startTime
.
doubleValue
];
httpModel
.
downFlow
=
[
NSString
stringWithFormat
:
@"%lli"
,[
DoraemonUrlUtil
getResponseLength
:(
NSHTTPURLResponse
*
)
response
data
:
responseData
]];
return
httpModel
;
[[
DoraemonNetFlowManager
shareInstance
]
httpBodyFromRequest
:
request
bodyCallBack
:
^
(
NSData
*
body
)
{
httpModel
.
requestBody
=
[
DoraemonUrlUtil
convertJsonFromData
:
body
];
NSUInteger
length
=
[
DoraemonUrlUtil
getHeadersLengthWithRequest
:
request
]
+
[
body
length
];
httpModel
.
uploadFlow
=
[
NSString
stringWithFormat
:
@"%zi"
,
length
];
complete
(
httpModel
);
}];
}
@end
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/DoraemonNetFlowManager.h
浏览文件 @
be415998
...
...
@@ -7,6 +7,8 @@
#import <Foundation/Foundation.h>
typedef
void
(
^
HttpBodyCallBack
)(
NSData
*
body
);
@interface
DoraemonNetFlowManager
:
NSObject
+
(
DoraemonNetFlowManager
*
)
shareInstance
;
...
...
@@ -16,4 +18,6 @@
-
(
void
)
canInterceptNetFlow
:(
BOOL
)
enable
;
-
(
void
)
httpBodyFromRequest
:(
NSURLRequest
*
)
request
bodyCallBack
:(
HttpBodyCallBack
)
complete
;
@end
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/DoraemonNetFlowManager.m
浏览文件 @
be415998
...
...
@@ -13,7 +13,10 @@
#import "UIViewController+Doraemon.h"
#import "DoraemonHealthManager.h"
@interface
DoraemonNetFlowManager
()
<
DoraemonNetworkInterceptorDelegate
>
@interface
DoraemonNetFlowManager
()
<
DoraemonNetworkInterceptorDelegate
,
NSStreamDelegate
>
@property
(
nonatomic
,
copy
)
HttpBodyCallBack
bodyCallBack
;
@property
(
nonatomic
,
strong
)
NSMutableData
*
bodyData
;
@end
...
...
@@ -40,21 +43,79 @@
}
}
-
(
void
)
httpBodyFromRequest
:(
NSURLRequest
*
)
request
bodyCallBack
:(
HttpBodyCallBack
)
complete
{
NSData
*
httpBody
=
nil
;
if
(
request
.
HTTPBody
)
{
httpBody
=
request
.
HTTPBody
;
complete
(
httpBody
);
return
;
}
if
([
request
.
HTTPMethod
isEqualToString
:
@"POST"
])
{
NSInputStream
*
stream
=
request
.
HTTPBodyStream
;
[
stream
setDelegate
:
self
];
self
.
bodyCallBack
=
complete
;
[
stream
scheduleInRunLoop
:[
NSRunLoop
currentRunLoop
]
forMode
:
NSDefaultRunLoopMode
];
[
stream
open
];
}
else
{
complete
(
httpBody
);
}
}
#pragma mark -- NSStreamDelegate
-
(
void
)
stream
:(
NSStream
*
)
aStream
handleEvent
:(
NSStreamEvent
)
eventCode
{
switch
(
eventCode
)
{
case
NSStreamEventHasBytesAvailable
:
{
if
(
!
self
.
bodyData
)
{
self
.
bodyData
=
[
NSMutableData
data
];
}
uint8_t
buf
[
1024
];
NSInteger
len
=
0
;
len
=
[(
NSInputStream
*
)
aStream
read
:
buf
maxLength
:
1024
];
if
(
len
)
{
[
self
.
bodyData
appendBytes
:(
const
void
*
)
buf
length
:
len
];
}
}
break
;
case
NSStreamEventErrorOccurred
:
{
NSError
*
error
=
[
aStream
streamError
];
NSString
*
errorInfo
=
[
NSString
stringWithFormat
:
@"Failed while reading stream; error '%@' (code %ld)"
,
error
.
localizedDescription
,
error
.
code
];
NSLog
(
@"%@"
,
errorInfo
);
}
break
;
case
NSStreamEventEndEncountered
:
{
[
aStream
close
];
[
aStream
removeFromRunLoop
:[
NSRunLoop
currentRunLoop
]
forMode
:
NSDefaultRunLoopMode
];
aStream
=
nil
;
if
(
self
.
bodyCallBack
)
{
self
.
bodyCallBack
([
self
.
bodyData
copy
]);
}
self
.
bodyData
=
nil
;
}
break
;
default:
break
;
}
}
#pragma mark -- DoraemonNetworkInterceptorDelegate
-
(
void
)
doraemonNetworkInterceptorDidReceiveData
:(
NSData
*
)
data
response
:(
NSURLResponse
*
)
response
request
:(
NSURLRequest
*
)
request
error
:(
NSError
*
)
error
startTime
:(
NSTimeInterval
)
startTime
{
DoraemonNetFlowHttpModel
*
httpModel
=
[
DoraemonNetFlowHttpModel
dealWithResponseData
:
data
response
:
response
request
:
request
];
if
(
!
response
)
{
httpModel
.
statusCode
=
error
.
localizedDescription
;
}
httpModel
.
startTime
=
startTime
;
httpModel
.
endTime
=
[[
NSDate
date
]
timeIntervalSince1970
];
httpModel
.
totalDuration
=
[
NSString
stringWithFormat
:
@"%f"
,[[
NSDate
date
]
timeIntervalSince1970
]
-
startTime
];
httpModel
.
topVc
=
NSStringFromClass
([[
UIViewController
topViewControllerForKeyWindow
]
class
]);
[[
DoraemonNetFlowDataSource
shareInstance
]
addHttpModel
:
httpModel
];
[[
DoraemonHealthManager
sharedInstance
]
addHttpModel
:
httpModel
];
[
DoraemonNetFlowHttpModel
dealWithResponseData
:
data
response
:
response
request
:
request
complete
:^
(
DoraemonNetFlowHttpModel
*
httpModel
)
{
if
(
!
response
)
{
httpModel
.
statusCode
=
error
.
localizedDescription
;
}
httpModel
.
startTime
=
startTime
;
httpModel
.
endTime
=
[[
NSDate
date
]
timeIntervalSince1970
];
httpModel
.
totalDuration
=
[
NSString
stringWithFormat
:
@"%f"
,[[
NSDate
date
]
timeIntervalSince1970
]
-
startTime
];
httpModel
.
topVc
=
NSStringFromClass
([[
UIViewController
topViewControllerForKeyWindow
]
class
]);
[[
DoraemonNetFlowDataSource
shareInstance
]
addHttpModel
:
httpModel
];
[[
DoraemonHealthManager
sharedInstance
]
addHttpModel
:
httpModel
];
}];
}
-
(
BOOL
)
shouldIntercept
{
...
...
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/Util/DoraemonUrlUtil.h
浏览文件 @
be415998
...
...
@@ -13,7 +13,9 @@
+
(
NSDictionary
*
)
convertDicFromData
:(
NSData
*
)
data
;
+
(
NSUInteger
)
getRequestLength
:(
NSURLRequest
*
)
request
;
+
(
NSUInteger
)
getHeadersLengthWithRequest
:(
NSURLRequest
*
)
request
;
+
(
void
)
requestLength
:(
NSURLRequest
*
)
request
callBack
:(
void
(
^
)(
NSUInteger
))
callBack
;
+
(
NSUInteger
)
getHeadersLength
:(
NSDictionary
*
)
headers
;
...
...
@@ -21,6 +23,4 @@
+
(
int64_t
)
getResponseLength
:(
NSHTTPURLResponse
*
)
response
data
:(
NSData
*
)
responseData
;
+
(
NSData
*
)
getHttpBodyFromRequest
:(
NSURLRequest
*
)
request
;
@end
iOS/DoraemonKit/Src/Core/Plugin/Performance/NetFlow/Function/Util/DoraemonUrlUtil.m
浏览文件 @
be415998
...
...
@@ -6,6 +6,7 @@
//
#import "DoraemonUrlUtil.h"
#import "DoraemonNetFlowManager.h"
@implementation
DoraemonUrlUtil
...
...
@@ -39,7 +40,15 @@
return
jsonObj
;
}
+
(
NSUInteger
)
getRequestLength
:(
NSURLRequest
*
)
request
{
+
(
void
)
requestLength
:(
NSURLRequest
*
)
request
callBack
:(
void
(
^
)(
NSUInteger
))
callBack
{
NSUInteger
headersLength
=
[
self
getHeadersLengthWithRequest
:
request
];
[[
DoraemonNetFlowManager
shareInstance
]
httpBodyFromRequest
:
request
bodyCallBack
:
^
(
NSData
*
body
)
{
NSUInteger
bodyLength
=
[
body
length
];
callBack
(
headersLength
+
bodyLength
);
}];
}
+
(
NSUInteger
)
getHeadersLengthWithRequest
:(
NSURLRequest
*
)
request
{
NSDictionary
<
NSString
*
,
NSString
*>
*
headerFields
=
request
.
allHTTPHeaderFields
;
NSDictionary
<
NSString
*
,
NSString
*>
*
cookiesHeader
=
[
self
getCookies
:
request
];
if
(
cookiesHeader
.
count
)
{
...
...
@@ -47,11 +56,7 @@
[
headerFieldsWithCookies
addEntriesFromDictionary
:
cookiesHeader
];
headerFields
=
[
headerFieldsWithCookies
copy
];
}
NSUInteger
headersLength
=
[
self
getHeadersLength
:
headerFields
];
NSData
*
httpBody
=
[[
self
class
]
getHttpBodyFromRequest
:
request
];
NSUInteger
bodyLength
=
[
httpBody
length
];
return
headersLength
+
bodyLength
;
return
[
self
getHeadersLength
:
headerFields
];
}
+
(
NSUInteger
)
getHeadersLength
:(
NSDictionary
*
)
headers
{
...
...
@@ -95,28 +100,4 @@
return
responseLength
;
}
+
(
NSData
*
)
getHttpBodyFromRequest
:(
NSURLRequest
*
)
request
{
NSData
*
httpBody
;
if
(
request
.
HTTPBody
)
{
httpBody
=
request
.
HTTPBody
;
}
else
{
if
([
request
.
HTTPMethod
isEqualToString
:
@"POST"
])
{
if
(
!
request
.
HTTPBody
)
{
uint8_t
d
[
1024
]
=
{
0
};
NSInputStream
*
stream
=
request
.
HTTPBodyStream
;
NSMutableData
*
data
=
[[
NSMutableData
alloc
]
init
];
[
stream
open
];
while
([
stream
hasBytesAvailable
])
{
NSInteger
len
=
[
stream
read
:
d
maxLength
:
1024
];
if
(
len
>
0
&&
stream
.
streamError
==
nil
)
{
[
data
appendBytes
:(
void
*
)
d
length
:
len
];
}
}
httpBody
=
[
data
copy
];
[
stream
close
];
}
}
}
return
httpBody
;
}
@end
iOS/DoraemonKit/Src/Core/Plugin/Performance/WeakNetwork/Function/DoraemonWeakNetworkManager.m
浏览文件 @
be415998
...
...
@@ -115,7 +115,9 @@
#pragma mark -- DoraemonNetworkInterceptorDelegate
-
(
void
)
doraemonNetworkInterceptorDidReceiveData
:(
NSData
*
)
data
response
:(
NSURLResponse
*
)
response
request
:(
NSURLRequest
*
)
request
error
:(
NSError
*
)
error
startTime
:(
NSTimeInterval
)
startTime
{
[[
DoraemonWeakNetworkWindow
shareInstance
]
updateFlowValue
:[
NSString
stringWithFormat
:
@"%zi"
,[
DoraemonUrlUtil
getRequestLength
:
request
]]
downFlow
:[
NSString
stringWithFormat
:
@"%lli"
,[
DoraemonUrlUtil
getResponseLength
:(
NSHTTPURLResponse
*
)
response
data
:
data
]]
fromWeak
:
NO
];
[
DoraemonUrlUtil
requestLength
:
request
callBack
:
^
(
NSUInteger
length
)
{
[[
DoraemonWeakNetworkWindow
shareInstance
]
updateFlowValue
:[
NSString
stringWithFormat
:
@"%zi"
,
length
]
downFlow
:[
NSString
stringWithFormat
:
@"%lli"
,[
DoraemonUrlUtil
getResponseLength
:(
NSHTTPURLResponse
*
)
response
data
:
data
]]
fromWeak
:
NO
];
}];
}
-
(
BOOL
)
shouldIntercept
{
...
...
iOS/DoraemonKit/Src/Core/Plugin/Platform/Mock/Function/DoraemonMockManager.m
浏览文件 @
be415998
...
...
@@ -59,6 +59,7 @@
-
(
void
)
queryMockData
:(
void
(
^
)(
int
flag
))
block
{
NSString
*
pId
=
[
DoraemonManager
shareInstance
].
pId
;
NSString
*
mockDomain
=
[
DoraemonManager
shareInstance
].
mockDomain
?
[
DoraemonManager
shareInstance
].
mockDomain
:
@"https://mock.dokit.cn/"
;
if
(
pId
&&
pId
.
length
>
0
)
{
NSDictionary
*
params
=
@{
@"projectId"
:
pId
,
...
...
@@ -68,7 +69,8 @@
};
__weak
typeof
(
self
)
weakSelf
=
self
;
[
DoraemonNetworkUtil
getWithUrlString
:
@"https://mock.dokit.cn/api/app/interface"
params
:
params
success
:^
(
NSDictionary
*
_Nonnull
result
)
{
NSString
*
mockInterfaceUrl
=
[
mockDomain
stringByAppendingString
:
@"api/app/interface"
];
[
DoraemonNetworkUtil
getWithUrlString
:
mockInterfaceUrl
params
:
params
success
:^
(
NSDictionary
*
_Nonnull
result
)
{
NSArray
*
apis
=
result
[
@"data"
][
@"datalist"
];
NSMutableArray
<
DoraemonMockAPIModel
*>
*
mockArray
=
[[
NSMutableArray
alloc
]
init
];
NSMutableArray
<
DoraemonMockUpLoadModel
*>
*
uploadArray
=
[[
NSMutableArray
alloc
]
init
];
...
...
@@ -181,7 +183,8 @@
-
(
DoraemonMockBaseModel
*
)
getSelectedData
:(
NSURLRequest
*
)
request
dataArray
:(
NSArray
*
)
dataArray
{
NSString
*
path
=
request
.
URL
.
path
;
NSString
*
query
=
request
.
URL
.
query
;
NSData
*
httpBody
=
[
DoraemonUrlUtil
getHttpBodyFromRequest
:
request
];
// 这里暂时使用不严谨body match
NSData
*
httpBody
=
request
.
HTTPBody
;
NSDictionary
*
requestBody
=
[
DoraemonUrlUtil
convertDicFromData
:
httpBody
];
DoraemonMockBaseModel
*
selectedApi
;
for
(
DoraemonMockBaseModel
*
api
in
dataArray
)
{
...
...
@@ -329,7 +332,7 @@
NSString
*
apiId
=
upload
.
apiId
;
NSString
*
result
=
upload
.
result
;
NSString
*
projectId
=
[
DoraemonManager
shareInstance
].
pId
;
NSString
*
mockDomain
=
[
DoraemonManager
shareInstance
].
mockDomain
?
[
DoraemonManager
shareInstance
].
mockDomain
:
@"https://mock.dokit.cn/"
;
if
(
projectId
&&
projectId
.
length
>
0
)
{
if
(
!
result
)
{
return
;
...
...
@@ -340,8 +343,8 @@
@"id"
:
apiId
,
@"tempData"
:
result
};
[
DoraemonNetworkUtil
patchWithUrlString
:
@"https://mock.dokit.cn/api/app/interface"
params
:
params
success
:^
(
NSDictionary
*
_Nonnull
result
)
{
NSString
*
mockInterfaceUrl
=
[
mockDomain
stringByAppendingString
:
@"api/app/interface"
];
[
DoraemonNetworkUtil
patchWithUrlString
:
mockInterfaceUrl
params
:
params
success
:^
(
NSDictionary
*
_Nonnull
result
)
{
[
self
showToast
:
DoraemonLocalizedString
(
@"上传成功"
)
atView
:
view
];
}
error
:^
(
NSError
*
_Nonnull
error
)
{
DoKitLog
(
@"error == %@"
,
error
);
...
...
iOS/DoraemonKitDemo/DoraemonKitDemo/DemoVC/Net/ NSURLProtocol/DoraemonDemoURLProtocol1.m
浏览文件 @
be415998
...
...
@@ -8,6 +8,7 @@
#import "DoraemonDemoURLProtocol1.h"
#import "DoraemonUrlUtil.h"
#import "DoraemonNetFlowManager.h"
static
NSString
*
const
kDoraemonDemoUrlProtocolKey
=
@"doraemon_demo_url_protocol_1_key"
;
...
...
@@ -48,10 +49,11 @@ static NSString * const kDoraemonDemoUrlProtocolKey = @"doraemon_demo_url_protoc
-
(
void
)
stopLoading
{
NSLog
(
@"11111 == stopLoading"
);
NSData
*
httpBody
=
[
DoraemonUrlUtil
getHttpBodyFromRequest
:
self
.
request
];
NSString
*
requestBody
=
[
DoraemonUrlUtil
convertJsonFromData
:
httpBody
];
NSLog
(
@"11111 == requestBody = %@"
,
requestBody
);
[
self
.
connection
cancel
];
[[
DoraemonNetFlowManager
shareInstance
]
httpBodyFromRequest
:
self
.
request
bodyCallBack
:
^
(
NSData
*
httpBody
)
{
NSString
*
requestBody
=
[
DoraemonUrlUtil
convertJsonFromData
:
httpBody
];
NSLog
(
@"11111 == requestBody = %@"
,
requestBody
);
[
self
.
connection
cancel
];
}];
}
...
...
iOS/DoraemonKitDemo/DoraemonKitDemo/DemoVC/Net/ NSURLProtocol/DoraemonDemoURLProtocol2.m
浏览文件 @
be415998
...
...
@@ -8,6 +8,7 @@
#import "DoraemonDemoURLProtocol2.h"
#import "DoraemonUrlUtil.h"
#import "DoraemonNetFlowManager.h"
static
NSString
*
const
kDoraemonDemoUrlProtocol2Key
=
@"doraemon_demo_url_protocol_2_key"
;
...
...
@@ -48,10 +49,11 @@ static NSString * const kDoraemonDemoUrlProtocol2Key = @"doraemon_demo_url_proto
-
(
void
)
stopLoading
{
NSLog
(
@"22222 == stopLoading"
);
NSData
*
httpBody
=
[
DoraemonUrlUtil
getHttpBodyFromRequest
:
self
.
request
];
NSString
*
requestBody
=
[
DoraemonUrlUtil
convertJsonFromData
:
httpBody
];
NSLog
(
@"22222 == requestBody = %@"
,
requestBody
);
[
self
.
connection
cancel
];
[[
DoraemonNetFlowManager
shareInstance
]
httpBodyFromRequest
:
self
.
request
bodyCallBack
:
^
(
NSData
*
httpBody
)
{
NSString
*
requestBody
=
[
DoraemonUrlUtil
convertJsonFromData
:
httpBody
];
NSLog
(
@"22222 == requestBody = %@"
,
requestBody
);
[
self
.
connection
cancel
];
}];
}
...
...
iOS/DoraemonKitDemo/DoraemonKitDemo/DemoVC/Net/DoraemonDemoNetViewController.m
浏览文件 @
be415998
...
...
@@ -222,10 +222,11 @@
session
.
requestSerializer
=
[
AFHTTPRequestSerializer
serializer
];
// 请求
session
.
responseSerializer
=
[
AFHTTPResponseSerializer
serializer
];
// 响应
session
.
responseSerializer
.
acceptableContentTypes
=
[
NSSet
setWithObjects
:
@"application/json"
,
@"text/json"
,
@"text/javascript"
,
@"text/html"
,
nil
];
[
session
GET
:
@"https://www.taobao.com/"
parameters
:
nil
success
:^
(
NSURLSessionDataTask
*
task
,
id
responseObject
)
{
[
session
GET
:
@"https://www.taobao.com/"
parameters
:
nil
headers
:
nil
progress
:
nil
success
:^
(
NSURLSessionDataTask
*
_Nonnull
task
,
id
_Nullable
responseObject
)
{
NSString
*
string
=
[[
NSString
alloc
]
initWithData
:
responseObject
encoding
:
NSUTF8StringEncoding
];
NSLog
(
@"success %@"
,
string
);
}
failure
:^
(
NSURLSessionDataTask
*
task
,
NSError
*
error
)
{
}
failure
:^
(
NSURLSessionDataTask
*
_Nullable
task
,
NSError
*
_Nonnull
error
)
{
NSLog
(
@"failure"
);
}];
...
...
@@ -238,7 +239,7 @@
}
-
(
void
)
netForAFNetworking2
{
AFHTTP
RequestOperationManager
*
manager
=
[
AFHTTPRequestOperat
ionManager
manager
];
AFHTTP
SessionManager
*
manager
=
[
AFHTTPSess
ionManager
manager
];
manager
.
requestSerializer
=
[
AFHTTPRequestSerializer
serializer
];
// 请求
manager
.
responseSerializer
=
[
AFHTTPResponseSerializer
serializer
];
// 响应
manager
.
responseSerializer
.
acceptableContentTypes
=
[
NSSet
setWithObjects
:
@"application/json"
,
@"text/json"
,
@"text/javascript"
,
@"text/html"
,
nil
];
...
...
@@ -249,10 +250,10 @@
// NSLog(@"请求失败");
// }];
[
manager
POST
:
@"https://www.taobao.com/"
parameters
:
nil
success
:^
(
AFHTTPRequestOperation
*
operation
,
id
responseObject
)
{
[
manager
POST
:
@"https://www.taobao.com/"
parameters
:
nil
headers
:
nil
progress
:
nil
success
:^
(
NSURLSessionDataTask
*
_Nonnull
task
,
id
_Nullable
responseObject
)
{
NSString
*
string
=
[[
NSString
alloc
]
initWithData
:
responseObject
encoding
:
NSUTF8StringEncoding
];
NSLog
(
@"success %@"
,
string
);
}
failure
:^
(
AFHTTPRequestOperation
*
operation
,
NSError
*
error
)
{
}
failure
:^
(
NSURLSessionDataTask
*
_Nullable
task
,
NSError
*
_Nonnull
error
)
{
NSLog
(
@"failure"
);
}];
}
...
...
iOS/DoraemonKitDemo/DoraemonKitDemo/DemoVC/Performance/DoraemonDemoPerformanceViewController.m
浏览文件 @
be415998
...
...
@@ -130,14 +130,15 @@
// NSLog(@"请求失败");
// }];
AFHTTP
RequestOperationManager
*
manager
=
[
AFHTTPRequestOperat
ionManager
manager
];
AFHTTP
SessionManager
*
manager
=
[
AFHTTPSess
ionManager
manager
];
manager
.
requestSerializer
=
[
AFHTTPRequestSerializer
serializer
];
// 请求
manager
.
responseSerializer
=
[
AFHTTPResponseSerializer
serializer
];
// 响应
manager
.
responseSerializer
.
acceptableContentTypes
=
[
NSSet
setWithObjects
:
@"application/json"
,
@"text/json"
,
@"text/javascript"
,
@"text/html"
,
nil
];
[
manager
GET
:
@"https://www.taobao.com/"
parameters
:
nil
success
:^
(
AFHTTPRequestOperation
*
operation
,
id
responseObject
)
{
[
manager
GET
:
@"https://www.taobao.com/"
parameters
:
nil
headers
:
nil
progress
:
nil
success
:^
(
NSURLSessionDataTask
*
_Nonnull
task
,
id
_Nullable
responseObject
)
{
NSString
*
string
=
[[
NSString
alloc
]
initWithData
:
responseObject
encoding
:
NSUTF8StringEncoding
];
NSLog
(
@"request success %@"
,
string
);
}
failure
:^
(
AFHTTPRequestOperation
*
operation
,
NSError
*
error
)
{
}
failure
:^
(
NSURLSessionDataTask
*
_Nullable
task
,
NSError
*
_Nonnull
error
)
{
NSLog
(
@"request failure"
);
}];
}
...
...
iOS/DoraemonKitDemo/Podfile
浏览文件 @
be415998
...
...
@@ -20,7 +20,7 @@ target :'DoraemonKitDemo' do
#pod 'DoraemonKit', :subspecs => ['Core','WithLogger','WithGPS','WithLoad','WithWeex', 'WithDatabase', 'WithMLeaksFinder'], :path => '../../'
#pod 'DoraemonKit', :subspecs => ['Core'], :path => '../../'
pod
'DoraemonKit'
,
:subspecs
=>
[
'Core'
,
'WithLogger'
,
'WithGPS'
,
'WithLoad'
,
'WithDatabase'
,
'WithMLeaksFinder'
,
'WithWeex'
],
:path
=>
'../../'
pod
'AFNetworking'
,
'2.6.3'
pod
'AFNetworking'
pod
'SDWebImage'
pod
'SocketRocket'
,
'~> 0.5'
pod
'SDWebImageWebPCoder'
...
...
iOS/DoraemonKitDemo/Podfile.lock
浏览文件 @
be415998
PODS:
- AFNetworking (2.6.3):
- AFNetworking/NSURLConnection (= 2.6.3)
- AFNetworking/NSURLSession (= 2.6.3)
- AFNetworking/Reachability (= 2.6.3)
- AFNetworking/Security (= 2.6.3)
- AFNetworking/Serialization (= 2.6.3)
- AFNetworking/UIKit (= 2.6.3)
- AFNetworking/NSURLConnection (2.6.3):
- AFNetworking (4.0.1):
- AFNetworking/NSURLSession (= 4.0.1)
- AFNetworking/Reachability (= 4.0.1)
- AFNetworking/Security (= 4.0.1)
- AFNetworking/Serialization (= 4.0.1)
- AFNetworking/UIKit (= 4.0.1)
- AFNetworking/NSURLSession (4.0.1):
- AFNetworking/Reachability
- AFNetworking/Security
- AFNetworking/Serialization
- AFNetworking/NSURLSession (2.6.3):
- AFNetworking/Reachability
- AFNetworking/Security
- AFNetworking/Serialization
- AFNetworking/Reachability (2.6.3)
- AFNetworking/Security (2.6.3)
- AFNetworking/Serialization (2.6.3)
- AFNetworking/UIKit (2.6.3):
- AFNetworking/NSURLConnection
- AFNetworking/Reachability (4.0.1)
- AFNetworking/Security (4.0.1)
- AFNetworking/Serialization (4.0.1)
- AFNetworking/UIKit (4.0.1):
- AFNetworking/NSURLSession
- CocoaLumberjack (3.
6.2
):
- CocoaLumberjack/Core (= 3.
6.2
)
- CocoaLumberjack/Core (3.
6.2
)
- CocoaLumberjack (3.
7.0
):
- CocoaLumberjack/Core (= 3.
7.0
)
- CocoaLumberjack/Core (3.
7.0
)
- DoraemonKit/Core (3.0.6):
- FMDB
- GCDWebServer
...
...
@@ -65,12 +59,12 @@ PODS:
- libwebp/mux (1.1.0):
- libwebp/demux
- libwebp/webp (1.1.0)
- SDWebImage (5.
8
.4):
- SDWebImage/Core (= 5.
8
.4)
- SDWebImage/Core (5.
8
.4)
- SDWebImageWebPCoder (0.
6.1
):
- SDWebImage (5.
10
.4):
- SDWebImage/Core (= 5.
10
.4)
- SDWebImage/Core (5.
10
.4)
- SDWebImageWebPCoder (0.
8.2
):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.
7
)
- SDWebImage/Core (~> 5.
10
)
- SocketRocket (0.5.1)
- WeexSDK (0.28.0)
- WXDevtool (0.24.0):
...
...
@@ -81,7 +75,7 @@ PODS:
- GCDWebServer
DEPENDENCIES:
- AFNetworking
(= 2.6.3)
- AFNetworking
- DoraemonKit/Core (from `../../`)
- DoraemonKit/WithDatabase (from `../../`)
- DoraemonKit/WithGPS (from `../../`)
...
...
@@ -118,27 +112,27 @@ EXTERNAL SOURCES:
CHECKOUT OPTIONS:
FBRetainCycleDetector:
:commit:
1ff2adee84a6ee94a1ae82526104a188774eb90a
:commit:
32c4afc1fc17553f9b69e4edd82cfa3c73dbb331
:git: https://github.com/facebook/FBRetainCycleDetector.git
YYDebugDatabase:
:commit: 87f4214ab9656b75dd74dfcc042cc3b5067ebab6
:git: https://github.com/y500/YYDebugDatabase.git
SPEC CHECKSUMS:
AFNetworking:
cb8d14a848e831097108418f5d49217339d4eb60
CocoaLumberjack:
bd155f2dd06c0e0b03f876f7a3ee55693122ec94
AFNetworking:
7864c38297c79aaca1500c33288e429c3451fdce
CocoaLumberjack:
e8955b9d337ac307103b0a34fd141c32f27e53c5
DoraemonKit: 919709427c30af94e265532a879ac41797d296d1
FBRetainCycleDetector: 46daef95c2dfa9be34b53087edf6a8f34e4c749c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
SDWebImage: c
f6922231e95550934da2ada0f20f2becf2ceba9
SDWebImageWebPCoder:
d0dac55073088d24b2ac1b191a71a8f8d0adac21
SDWebImage: c
666b97e1fa9c64b4909816a903322018f0a9c84
SDWebImageWebPCoder:
f56ab499e3ea57dfeb6c3187dce183b10e160db0
SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531
WeexSDK: 78861d2f8b78f67e30580c15a54f5b420456db39
WXDevtool: 95b70c73c06fc3299d65bd53ba4b3e0b0087f3cb
YYDebugDatabase: e684a7f79fca2e3673a23347cefb822f911f3124
PODFILE CHECKSUM:
6c5cced982a83d1a6dbfb6e8501724985d70d130
PODFILE CHECKSUM:
a955cdaf3e59b0dc21224f229ea928cf97cc0173
COCOAPODS: 1.
10.1
COCOAPODS: 1.
8.4
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录