├── Doc ├── Fastbot-Xcode-BundleId.png ├── Fastbot-Xcode-IDE.png ├── Fastbot-Xcode-Scheme.png ├── Fastbot-Xcode-Sign.png ├── Fastbot-Xcode-Sign1.png ├── Fastbot-XcodeRunTest.png ├── TestOpenNetwork.png ├── TestOpenNetwork1.png ├── Xcode-SetArgs.png ├── Xcode-SetArgs0.png ├── Xcode-SetTarget.png ├── XcodePrefreence.png ├── XcodeStopTest.png └── handbook-cn.md ├── Fastbot-iOS ├── Fastbot-iOS.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── FastbotRunner.xcscheme │ │ └── fastbot_stub.xcscheme ├── FastbotRunner │ ├── FastbotRunner.m │ └── Info.plist ├── Podfile ├── fastbot-stub.podspec ├── fastbot-stub │ ├── stub.h │ └── stub.m ├── fastbot.podspec └── fastbot │ ├── FastbotLib.framework │ ├── FastbotLib │ └── Info.plist │ ├── Headers │ └── fastbot_native.h │ ├── fastbot_cv.framework │ ├── Info.plist │ ├── fastbot_cv │ └── fastbot_cv.bundle │ │ └── config │ │ ├── appconfig.json │ │ ├── default.jsonsetting │ │ ├── default.setting │ │ ├── setting.json │ │ └── testconfig.json │ └── fastbot_native.framework │ ├── Info.plist │ └── fastbot_native ├── LICENSE └── Readme.md /Doc/Fastbot-Xcode-BundleId.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Fastbot-Xcode-BundleId.png -------------------------------------------------------------------------------- /Doc/Fastbot-Xcode-IDE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Fastbot-Xcode-IDE.png -------------------------------------------------------------------------------- /Doc/Fastbot-Xcode-Scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Fastbot-Xcode-Scheme.png -------------------------------------------------------------------------------- /Doc/Fastbot-Xcode-Sign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Fastbot-Xcode-Sign.png -------------------------------------------------------------------------------- /Doc/Fastbot-Xcode-Sign1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Fastbot-Xcode-Sign1.png -------------------------------------------------------------------------------- /Doc/Fastbot-XcodeRunTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Fastbot-XcodeRunTest.png -------------------------------------------------------------------------------- /Doc/TestOpenNetwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/TestOpenNetwork.png -------------------------------------------------------------------------------- /Doc/TestOpenNetwork1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/TestOpenNetwork1.png -------------------------------------------------------------------------------- /Doc/Xcode-SetArgs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Xcode-SetArgs.png -------------------------------------------------------------------------------- /Doc/Xcode-SetArgs0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Xcode-SetArgs0.png -------------------------------------------------------------------------------- /Doc/Xcode-SetTarget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/Xcode-SetTarget.png -------------------------------------------------------------------------------- /Doc/XcodePrefreence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/XcodePrefreence.png -------------------------------------------------------------------------------- /Doc/XcodeStopTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Doc/XcodeStopTest.png -------------------------------------------------------------------------------- /Doc/handbook-cn.md: -------------------------------------------------------------------------------- 1 | 针对新手的更详细的补充使用手册: 2 | 3 | -------- 4 | 5 | ## 环境准备(一次性工作) 6 | 如果已有对应环境则跳过相关步骤即可。 7 | 1. osx 环境:准备 Mac 机器 8 | * xcode 环境: [下载安装 XcodeIDE](https://developer.apple.com/xcode/resources/) 9 | * 安装 cocoapods: 在终端中执行 `sudo gem install cocoapods -v=1.8.1` , 并按提示输入设备登录密码 10 | 2. 初始化项目: 11 | * 在终端 cd 到当前项目目录下, 然后执行 `cd Fastbot-iOS && pod install --repo-update` 12 | * 打开项目:双击使用 XCode 打开项目目录下 `Fastbot-iOS/Fastbot-iOS.xcworkspace` 13 | * 设置签名:设置签名为`自动签名`, 修改`Bundle ID`为自己的 bundleid, 注意这里的BundleId必须是唯一的。 ![签名](./Fastbot-Xcode-Sign.png)![签名](./Fastbot-Xcode-Sign1.png) ![Bundle ID](./Fastbot-Xcode-BundleId.png) 14 | * 如果 xcode 中还未登录账号,请在Xcode的设置 中登录账号,如果还没有苹果账号,请先到[苹果官网](https://appleid.apple.com/account)注册一个账号![Xcode的设置](./XcodePrefreence.png) 15 | 3. 信任设备&Runner: 16 | * 信任设备:连接手机到电脑,并在手机中弹出的对话窗中选择`信任`,然后在 XcodeIDE 中选择构建目标为连接的设备或模拟器![Set Target](./Xcode-SetTarget.png) 17 | * 信任 FastbotRunner 工具: 执行 `pingTestNetwork`,待 FastbotRunner 安装成功后, 然后在手机 `设置-通用-设备管理-开发者App`中信任 FastbotRunner的证书。 18 | ![](./TestOpenNetwork.png) 19 | 4. 打开 FastbotRunner 网络权限: 执行 `pingTestNetwork`(此处可参照步骤3-2),此时在手机上点击 `FastbotRunner-Runner` App,弹出黑色界面后,等待 30s 左右,点击 Home 键(或屏幕底部上滑)回到桌面,此时弹出是否打开网络权限的弹窗,选择无线网络或蜂窝网即可。直到 Xcode 运行 log 中出现 `ping network success` 则打开网络成功,如果不成功可尝试重复步骤4 ![](./TestOpenNetwork1.png) 20 | ----- 21 | 22 | ----- 23 | ## 开始测试 24 | 1. 确定被测试App已经安装到设备中,并且可正常运行(即已经信任,如果是未信任可参照环境准备中的步骤3-2信任证书) 25 | 2. 在运行 Scheme 中设置测试参数,参数含义参照下表: 26 | 27 | |字段|说明|示例| 28 | |--|--|--| 29 | | BUNDLEID|被测试App的 Bundle ID|com.apple.Pages 30 | |duration|测试时长,单位分钟| 240 31 | |launchenv|启动测试App的环境变量,一般为空,或者以 ':'分割的key=value形式|isAutoTestUI=1:channel=AutoTest 32 | |throttle|操作间隔,单位毫秒|300 33 | 34 | ![](./Xcode-SetArgs0.png)![](./Xcode-SetArgs.png) 35 | 36 | 3. 执行测试,然后可在手机上观测到被测试App已经被拉起,并开始自动执行操作。![](./Fastbot-XcodeRunTest.png) 37 | 38 | ----- 39 | ### 其他说明 40 | 1. 如何获取crash报告: [#2](https://github.com/bytedance/Fastbot_iOS/issues/2) 41 | 2. 如何在 Win/Linux 下运行工具: 参考 tidevice [#1](https://github.com/bytedance/Fastbot_iOS/issues/1) 42 | 3. CI/CD 相关问题: 43 | 44 | * 终端执行可使用tidevice 或 xcodebuild 命令: 45 | 46 | `BUNDLEID=com.apple.Pages duration=240 throttle=300 xcodebuild test -workspace Fastbot-iOS.xcworkspace -scheme FastbotRunner -configuration Release -destination 'platform=iOS,id=00008030-001804563E44802E' -only-testing:FastbotRunner/FastbotRunner/testFastbot 47 | ` (如果启动Scheme设置中的启动参数被更改则需还原),可根据实际情况使用`build-for-testing` `test-without-building` 等提升执行效率 48 | * 证书信任问题: 安装一个一直不删除的相同证书的其他应用即可。 49 | 50 | 4. 如何自定义处理系统弹窗: 反注释 [代码块](../Fastbot-iOS/FastbotRunner/FastbotRunner.m#L57),并编写自定义逻辑即可 51 | 5. 更多高级功能可参考 [Fastbot跨平台](https://mp.weixin.qq.com/s/QhzqBFZygkIS6C69__smyQ),欢迎大家提交 MR 扩展 fastbot-stub.m 相关功能 52 | 53 | -------------------------------------------------------------------------------- /Fastbot-iOS/Fastbot-iOS.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1E83392B07987FA9E8989A4B /* libPods-FastbotRunner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF0490E8604F5FBBF80D1F /* libPods-FastbotRunner.a */; }; 11 | 4473C73D266CD9FD00843097 /* FastbotRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 4473C73C266CD9FD00843097 /* FastbotRunner.m */; }; 12 | D5F212E84D7D096B951E8C2A /* libPods-fastbot_stub.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89AEF58FECF73B0B1557BEEF /* libPods-fastbot_stub.a */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXFileReference section */ 16 | 172E1A8C4C8BF15FF6DE73CC /* Pods-fastbot-stub.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fastbot-stub.release.xcconfig"; path = "Target Support Files/Pods-fastbot-stub/Pods-fastbot-stub.release.xcconfig"; sourceTree = ""; }; 17 | 284E23100719BE532F9168D9 /* Pods-fastbot-stub.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fastbot-stub.debug.xcconfig"; path = "Target Support Files/Pods-fastbot-stub/Pods-fastbot-stub.debug.xcconfig"; sourceTree = ""; }; 18 | 3A4ED9D4FC45E91318F8516B /* Pods-fastbot_stub.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fastbot_stub.debug.xcconfig"; path = "Target Support Files/Pods-fastbot_stub/Pods-fastbot_stub.debug.xcconfig"; sourceTree = ""; }; 19 | 4459C8A62698521000E7989A /* fastbot_stub.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = fastbot_stub.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | 4473C73A266CD9FD00843097 /* FastbotRunner.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FastbotRunner.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 4473C73C266CD9FD00843097 /* FastbotRunner.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FastbotRunner.m; sourceTree = ""; }; 22 | 4473C73E266CD9FD00843097 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 23 | 5CEF352EF7E2003A9E671C29 /* Pods-FastbotRunner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FastbotRunner.debug.xcconfig"; path = "Target Support Files/Pods-FastbotRunner/Pods-FastbotRunner.debug.xcconfig"; sourceTree = ""; }; 24 | 6D17781D29CD54840C7AB700 /* Pods-FastbotRunner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FastbotRunner.release.xcconfig"; path = "Target Support Files/Pods-FastbotRunner/Pods-FastbotRunner.release.xcconfig"; sourceTree = ""; }; 25 | 70AF5AF3A59D92C88C4417E3 /* Pods-fastbot_stub.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fastbot_stub.release.xcconfig"; path = "Target Support Files/Pods-fastbot_stub/Pods-fastbot_stub.release.xcconfig"; sourceTree = ""; }; 26 | 76CBBF7CA85E61E56361466E /* libPods-fastbot-stub.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-fastbot-stub.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 84DF0490E8604F5FBBF80D1F /* libPods-FastbotRunner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FastbotRunner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 89AEF58FECF73B0B1557BEEF /* libPods-fastbot_stub.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-fastbot_stub.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 4459C8A32698521000E7989A /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | D5F212E84D7D096B951E8C2A /* libPods-fastbot_stub.a in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | 4473C737266CD9FD00843097 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | 1E83392B07987FA9E8989A4B /* libPods-FastbotRunner.a in Frameworks */, 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | /* End PBXFrameworksBuildPhase section */ 49 | 50 | /* Begin PBXGroup section */ 51 | 4473C6F2266CD93400843097 = { 52 | isa = PBXGroup; 53 | children = ( 54 | 4473C73B266CD9FD00843097 /* FastbotRunner */, 55 | 4473C6FC266CD93400843097 /* Products */, 56 | FDEA23DB12DEB8FAA915971E /* Pods */, 57 | EE235221767C34E5DFF86098 /* Frameworks */, 58 | ); 59 | sourceTree = ""; 60 | }; 61 | 4473C6FC266CD93400843097 /* Products */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 4473C73A266CD9FD00843097 /* FastbotRunner.xctest */, 65 | 4459C8A62698521000E7989A /* fastbot_stub.framework */, 66 | ); 67 | name = Products; 68 | sourceTree = ""; 69 | }; 70 | 4473C73B266CD9FD00843097 /* FastbotRunner */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 4473C73C266CD9FD00843097 /* FastbotRunner.m */, 74 | 4473C73E266CD9FD00843097 /* Info.plist */, 75 | ); 76 | path = FastbotRunner; 77 | sourceTree = ""; 78 | }; 79 | EE235221767C34E5DFF86098 /* Frameworks */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 84DF0490E8604F5FBBF80D1F /* libPods-FastbotRunner.a */, 83 | 76CBBF7CA85E61E56361466E /* libPods-fastbot-stub.a */, 84 | 89AEF58FECF73B0B1557BEEF /* libPods-fastbot_stub.a */, 85 | ); 86 | name = Frameworks; 87 | sourceTree = ""; 88 | }; 89 | FDEA23DB12DEB8FAA915971E /* Pods */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 5CEF352EF7E2003A9E671C29 /* Pods-FastbotRunner.debug.xcconfig */, 93 | 6D17781D29CD54840C7AB700 /* Pods-FastbotRunner.release.xcconfig */, 94 | 284E23100719BE532F9168D9 /* Pods-fastbot-stub.debug.xcconfig */, 95 | 172E1A8C4C8BF15FF6DE73CC /* Pods-fastbot-stub.release.xcconfig */, 96 | 3A4ED9D4FC45E91318F8516B /* Pods-fastbot_stub.debug.xcconfig */, 97 | 70AF5AF3A59D92C88C4417E3 /* Pods-fastbot_stub.release.xcconfig */, 98 | ); 99 | path = Pods; 100 | sourceTree = ""; 101 | }; 102 | /* End PBXGroup section */ 103 | 104 | /* Begin PBXHeadersBuildPhase section */ 105 | 4459C8A12698521000E7989A /* Headers */ = { 106 | isa = PBXHeadersBuildPhase; 107 | buildActionMask = 2147483647; 108 | files = ( 109 | ); 110 | runOnlyForDeploymentPostprocessing = 0; 111 | }; 112 | /* End PBXHeadersBuildPhase section */ 113 | 114 | /* Begin PBXNativeTarget section */ 115 | 4459C8A52698521000E7989A /* fastbot_stub */ = { 116 | isa = PBXNativeTarget; 117 | buildConfigurationList = 4459C8AA2698521000E7989A /* Build configuration list for PBXNativeTarget "fastbot_stub" */; 118 | buildPhases = ( 119 | 86E3CCF78ED785CC4DFE186E /* [CP] Check Pods Manifest.lock */, 120 | 4459C8A12698521000E7989A /* Headers */, 121 | 4459C8A22698521000E7989A /* Sources */, 122 | 4459C8A32698521000E7989A /* Frameworks */, 123 | 4459C8A42698521000E7989A /* Resources */, 124 | ); 125 | buildRules = ( 126 | ); 127 | dependencies = ( 128 | ); 129 | name = fastbot_stub; 130 | productName = fastbot_stub; 131 | productReference = 4459C8A62698521000E7989A /* fastbot_stub.framework */; 132 | productType = "com.apple.product-type.framework"; 133 | }; 134 | 4473C739266CD9FD00843097 /* FastbotRunner */ = { 135 | isa = PBXNativeTarget; 136 | buildConfigurationList = 4473C73F266CD9FD00843097 /* Build configuration list for PBXNativeTarget "FastbotRunner" */; 137 | buildPhases = ( 138 | 509AB0D1C06DEF271F7CBB31 /* [CP] Check Pods Manifest.lock */, 139 | 4473C736266CD9FD00843097 /* Sources */, 140 | 4473C737266CD9FD00843097 /* Frameworks */, 141 | 4473C738266CD9FD00843097 /* Resources */, 142 | 21BC84810BAC0E6727B06F67 /* [CP] Embed Pods Frameworks */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = FastbotRunner; 149 | productName = FastbotRunner; 150 | productReference = 4473C73A266CD9FD00843097 /* FastbotRunner.xctest */; 151 | productType = "com.apple.product-type.bundle.ui-testing"; 152 | }; 153 | /* End PBXNativeTarget section */ 154 | 155 | /* Begin PBXProject section */ 156 | 4473C6F3266CD93400843097 /* Project object */ = { 157 | isa = PBXProject; 158 | attributes = { 159 | LastUpgradeCheck = 1220; 160 | TargetAttributes = { 161 | 4459C8A52698521000E7989A = { 162 | CreatedOnToolsVersion = 13.0; 163 | }; 164 | 4473C739266CD9FD00843097 = { 165 | CreatedOnToolsVersion = 12.2; 166 | }; 167 | }; 168 | }; 169 | buildConfigurationList = 4473C6F6266CD93400843097 /* Build configuration list for PBXProject "Fastbot-iOS" */; 170 | compatibilityVersion = "Xcode 9.3"; 171 | developmentRegion = en; 172 | hasScannedForEncodings = 0; 173 | knownRegions = ( 174 | en, 175 | Base, 176 | ); 177 | mainGroup = 4473C6F2266CD93400843097; 178 | productRefGroup = 4473C6FC266CD93400843097 /* Products */; 179 | projectDirPath = ""; 180 | projectRoot = ""; 181 | targets = ( 182 | 4473C739266CD9FD00843097 /* FastbotRunner */, 183 | 4459C8A52698521000E7989A /* fastbot_stub */, 184 | ); 185 | }; 186 | /* End PBXProject section */ 187 | 188 | /* Begin PBXResourcesBuildPhase section */ 189 | 4459C8A42698521000E7989A /* Resources */ = { 190 | isa = PBXResourcesBuildPhase; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | 4473C738266CD9FD00843097 /* Resources */ = { 197 | isa = PBXResourcesBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | }; 203 | /* End PBXResourcesBuildPhase section */ 204 | 205 | /* Begin PBXShellScriptBuildPhase section */ 206 | 21BC84810BAC0E6727B06F67 /* [CP] Embed Pods Frameworks */ = { 207 | isa = PBXShellScriptBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | ); 211 | inputFileListPaths = ( 212 | "${PODS_ROOT}/Target Support Files/Pods-FastbotRunner/Pods-FastbotRunner-frameworks-${CONFIGURATION}-input-files.xcfilelist", 213 | ); 214 | name = "[CP] Embed Pods Frameworks"; 215 | outputFileListPaths = ( 216 | "${PODS_ROOT}/Target Support Files/Pods-FastbotRunner/Pods-FastbotRunner-frameworks-${CONFIGURATION}-output-files.xcfilelist", 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | shellPath = /bin/sh; 220 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FastbotRunner/Pods-FastbotRunner-frameworks.sh\"\n"; 221 | showEnvVarsInLog = 0; 222 | }; 223 | 509AB0D1C06DEF271F7CBB31 /* [CP] Check Pods Manifest.lock */ = { 224 | isa = PBXShellScriptBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | ); 228 | inputFileListPaths = ( 229 | ); 230 | inputPaths = ( 231 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 232 | "${PODS_ROOT}/Manifest.lock", 233 | ); 234 | name = "[CP] Check Pods Manifest.lock"; 235 | outputFileListPaths = ( 236 | ); 237 | outputPaths = ( 238 | "$(DERIVED_FILE_DIR)/Pods-FastbotRunner-checkManifestLockResult.txt", 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | shellPath = /bin/sh; 242 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 243 | showEnvVarsInLog = 0; 244 | }; 245 | 86E3CCF78ED785CC4DFE186E /* [CP] Check Pods Manifest.lock */ = { 246 | isa = PBXShellScriptBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | ); 250 | inputFileListPaths = ( 251 | ); 252 | inputPaths = ( 253 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 254 | "${PODS_ROOT}/Manifest.lock", 255 | ); 256 | name = "[CP] Check Pods Manifest.lock"; 257 | outputFileListPaths = ( 258 | ); 259 | outputPaths = ( 260 | "$(DERIVED_FILE_DIR)/Pods-fastbot_stub-checkManifestLockResult.txt", 261 | ); 262 | runOnlyForDeploymentPostprocessing = 0; 263 | shellPath = /bin/sh; 264 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 265 | showEnvVarsInLog = 0; 266 | }; 267 | /* End PBXShellScriptBuildPhase section */ 268 | 269 | /* Begin PBXSourcesBuildPhase section */ 270 | 4459C8A22698521000E7989A /* Sources */ = { 271 | isa = PBXSourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | }; 277 | 4473C736266CD9FD00843097 /* Sources */ = { 278 | isa = PBXSourcesBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | 4473C73D266CD9FD00843097 /* FastbotRunner.m in Sources */, 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | /* End PBXSourcesBuildPhase section */ 286 | 287 | /* Begin XCBuildConfiguration section */ 288 | 4459C8AB2698521000E7989A /* Debug */ = { 289 | isa = XCBuildConfiguration; 290 | baseConfigurationReference = 3A4ED9D4FC45E91318F8516B /* Pods-fastbot_stub.debug.xcconfig */; 291 | buildSettings = { 292 | CODE_SIGN_STYLE = Automatic; 293 | CURRENT_PROJECT_VERSION = 1; 294 | DEFINES_MODULE = YES; 295 | DYLIB_COMPATIBILITY_VERSION = 1; 296 | DYLIB_CURRENT_VERSION = 1; 297 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 298 | GENERATE_INFOPLIST_FILE = YES; 299 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 300 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 301 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 302 | LD_RUNPATH_SEARCH_PATHS = ( 303 | "$(inherited)", 304 | "@executable_path/Frameworks", 305 | "@loader_path/Frameworks", 306 | ); 307 | MARKETING_VERSION = 1.0; 308 | PRODUCT_BUNDLE_IDENTIFIER = "bytedance.fastbot-stub"; 309 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 310 | SKIP_INSTALL = YES; 311 | SWIFT_EMIT_LOC_STRINGS = YES; 312 | TARGETED_DEVICE_FAMILY = "1,2"; 313 | VERSIONING_SYSTEM = "apple-generic"; 314 | VERSION_INFO_PREFIX = ""; 315 | }; 316 | name = Debug; 317 | }; 318 | 4459C8AC2698521000E7989A /* Release */ = { 319 | isa = XCBuildConfiguration; 320 | baseConfigurationReference = 70AF5AF3A59D92C88C4417E3 /* Pods-fastbot_stub.release.xcconfig */; 321 | buildSettings = { 322 | CODE_SIGN_STYLE = Automatic; 323 | CURRENT_PROJECT_VERSION = 1; 324 | DEFINES_MODULE = YES; 325 | DYLIB_COMPATIBILITY_VERSION = 1; 326 | DYLIB_CURRENT_VERSION = 1; 327 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 328 | GENERATE_INFOPLIST_FILE = YES; 329 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 330 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 331 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 332 | LD_RUNPATH_SEARCH_PATHS = ( 333 | "$(inherited)", 334 | "@executable_path/Frameworks", 335 | "@loader_path/Frameworks", 336 | ); 337 | MARKETING_VERSION = 1.0; 338 | PRODUCT_BUNDLE_IDENTIFIER = "bytedance.fastbot-stub"; 339 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 340 | SKIP_INSTALL = YES; 341 | SWIFT_EMIT_LOC_STRINGS = YES; 342 | TARGETED_DEVICE_FAMILY = "1,2"; 343 | VERSIONING_SYSTEM = "apple-generic"; 344 | VERSION_INFO_PREFIX = ""; 345 | }; 346 | name = Release; 347 | }; 348 | 4473C728266CD93C00843097 /* Debug */ = { 349 | isa = XCBuildConfiguration; 350 | buildSettings = { 351 | ALWAYS_SEARCH_USER_PATHS = NO; 352 | CLANG_ANALYZER_NONNULL = YES; 353 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 354 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 355 | CLANG_CXX_LIBRARY = "libc++"; 356 | CLANG_ENABLE_MODULES = YES; 357 | CLANG_ENABLE_OBJC_ARC = YES; 358 | CLANG_ENABLE_OBJC_WEAK = YES; 359 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 360 | CLANG_WARN_BOOL_CONVERSION = YES; 361 | CLANG_WARN_COMMA = YES; 362 | CLANG_WARN_CONSTANT_CONVERSION = YES; 363 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 364 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 365 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 366 | CLANG_WARN_EMPTY_BODY = YES; 367 | CLANG_WARN_ENUM_CONVERSION = YES; 368 | CLANG_WARN_INFINITE_RECURSION = YES; 369 | CLANG_WARN_INT_CONVERSION = YES; 370 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 371 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 372 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 373 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 374 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 375 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 376 | CLANG_WARN_STRICT_PROTOTYPES = YES; 377 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 378 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 379 | CLANG_WARN_UNREACHABLE_CODE = YES; 380 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 381 | COPY_PHASE_STRIP = NO; 382 | DEBUG_INFORMATION_FORMAT = dwarf; 383 | ENABLE_STRICT_OBJC_MSGSEND = YES; 384 | ENABLE_TESTABILITY = YES; 385 | GCC_C_LANGUAGE_STANDARD = gnu11; 386 | GCC_DYNAMIC_NO_PIC = NO; 387 | GCC_NO_COMMON_BLOCKS = YES; 388 | GCC_OPTIMIZATION_LEVEL = 0; 389 | GCC_PREPROCESSOR_DEFINITIONS = ( 390 | "DEBUG=1", 391 | "$(inherited)", 392 | ); 393 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 394 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 395 | GCC_WARN_UNDECLARED_SELECTOR = YES; 396 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 397 | GCC_WARN_UNUSED_FUNCTION = YES; 398 | GCC_WARN_UNUSED_VARIABLE = YES; 399 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 400 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 401 | MTL_FAST_MATH = YES; 402 | ONLY_ACTIVE_ARCH = YES; 403 | SDKROOT = iphoneos; 404 | }; 405 | name = Debug; 406 | }; 407 | 4473C729266CD93C00843097 /* Release */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | ALWAYS_SEARCH_USER_PATHS = NO; 411 | CLANG_ANALYZER_NONNULL = YES; 412 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 413 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 414 | CLANG_CXX_LIBRARY = "libc++"; 415 | CLANG_ENABLE_MODULES = YES; 416 | CLANG_ENABLE_OBJC_ARC = YES; 417 | CLANG_ENABLE_OBJC_WEAK = YES; 418 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 419 | CLANG_WARN_BOOL_CONVERSION = YES; 420 | CLANG_WARN_COMMA = YES; 421 | CLANG_WARN_CONSTANT_CONVERSION = YES; 422 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 423 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 424 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 425 | CLANG_WARN_EMPTY_BODY = YES; 426 | CLANG_WARN_ENUM_CONVERSION = YES; 427 | CLANG_WARN_INFINITE_RECURSION = YES; 428 | CLANG_WARN_INT_CONVERSION = YES; 429 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 430 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 431 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 432 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 433 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 434 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 435 | CLANG_WARN_STRICT_PROTOTYPES = YES; 436 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 437 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 438 | CLANG_WARN_UNREACHABLE_CODE = YES; 439 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 440 | COPY_PHASE_STRIP = NO; 441 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 442 | ENABLE_NS_ASSERTIONS = NO; 443 | ENABLE_STRICT_OBJC_MSGSEND = YES; 444 | GCC_C_LANGUAGE_STANDARD = gnu11; 445 | GCC_NO_COMMON_BLOCKS = YES; 446 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 447 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 448 | GCC_WARN_UNDECLARED_SELECTOR = YES; 449 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 450 | GCC_WARN_UNUSED_FUNCTION = YES; 451 | GCC_WARN_UNUSED_VARIABLE = YES; 452 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 453 | MTL_ENABLE_DEBUG_INFO = NO; 454 | MTL_FAST_MATH = YES; 455 | SDKROOT = iphoneos; 456 | VALIDATE_PRODUCT = YES; 457 | }; 458 | name = Release; 459 | }; 460 | 4473C740266CD9FD00843097 /* Debug */ = { 461 | isa = XCBuildConfiguration; 462 | baseConfigurationReference = 5CEF352EF7E2003A9E671C29 /* Pods-FastbotRunner.debug.xcconfig */; 463 | buildSettings = { 464 | CODE_SIGN_IDENTITY = "iPhone Developer"; 465 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "iPhone Developer"; 466 | CODE_SIGN_STYLE = Automatic; 467 | DEVELOPMENT_TEAM = ""; 468 | EXCLUDED_ARCHS = i386; 469 | INFOPLIST_FILE = FastbotRunner/Info.plist; 470 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 471 | LD_RUNPATH_SEARCH_PATHS = ( 472 | "$(inherited)", 473 | "@executable_path/Frameworks", 474 | "@loader_path/Frameworks", 475 | ); 476 | PRODUCT_BUNDLE_IDENTIFIER = bytedance.FastbotRunner; 477 | PRODUCT_NAME = "$(TARGET_NAME)"; 478 | PROVISIONING_PROFILE_SPECIFIER = ""; 479 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | }; 482 | name = Debug; 483 | }; 484 | 4473C741266CD9FD00843097 /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | baseConfigurationReference = 6D17781D29CD54840C7AB700 /* Pods-FastbotRunner.release.xcconfig */; 487 | buildSettings = { 488 | CODE_SIGN_IDENTITY = "iPhone Developer"; 489 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "iPhone Developer"; 490 | CODE_SIGN_STYLE = Automatic; 491 | DEVELOPMENT_TEAM = ""; 492 | EXCLUDED_ARCHS = i386; 493 | INFOPLIST_FILE = FastbotRunner/Info.plist; 494 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 495 | LD_RUNPATH_SEARCH_PATHS = ( 496 | "$(inherited)", 497 | "@executable_path/Frameworks", 498 | "@loader_path/Frameworks", 499 | ); 500 | PRODUCT_BUNDLE_IDENTIFIER = bytedance.FastbotRunner; 501 | PRODUCT_NAME = "$(TARGET_NAME)"; 502 | PROVISIONING_PROFILE_SPECIFIER = ""; 503 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; 504 | TARGETED_DEVICE_FAMILY = "1,2"; 505 | }; 506 | name = Release; 507 | }; 508 | /* End XCBuildConfiguration section */ 509 | 510 | /* Begin XCConfigurationList section */ 511 | 4459C8AA2698521000E7989A /* Build configuration list for PBXNativeTarget "fastbot_stub" */ = { 512 | isa = XCConfigurationList; 513 | buildConfigurations = ( 514 | 4459C8AB2698521000E7989A /* Debug */, 515 | 4459C8AC2698521000E7989A /* Release */, 516 | ); 517 | defaultConfigurationIsVisible = 0; 518 | defaultConfigurationName = Release; 519 | }; 520 | 4473C6F6266CD93400843097 /* Build configuration list for PBXProject "Fastbot-iOS" */ = { 521 | isa = XCConfigurationList; 522 | buildConfigurations = ( 523 | 4473C728266CD93C00843097 /* Debug */, 524 | 4473C729266CD93C00843097 /* Release */, 525 | ); 526 | defaultConfigurationIsVisible = 0; 527 | defaultConfigurationName = Release; 528 | }; 529 | 4473C73F266CD9FD00843097 /* Build configuration list for PBXNativeTarget "FastbotRunner" */ = { 530 | isa = XCConfigurationList; 531 | buildConfigurations = ( 532 | 4473C740266CD9FD00843097 /* Debug */, 533 | 4473C741266CD9FD00843097 /* Release */, 534 | ); 535 | defaultConfigurationIsVisible = 0; 536 | defaultConfigurationName = Release; 537 | }; 538 | /* End XCConfigurationList section */ 539 | }; 540 | rootObject = 4473C6F3266CD93400843097 /* Project object */; 541 | } 542 | -------------------------------------------------------------------------------- /Fastbot-iOS/Fastbot-iOS.xcodeproj/xcshareddata/xcschemes/FastbotRunner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 21 | 22 | 23 | 24 | 28 | 29 | 33 | 34 | 38 | 39 | 43 | 44 | 48 | 49 | 50 | 51 | 53 | 59 | 60 | 61 | 62 | 63 | 73 | 74 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Fastbot-iOS/Fastbot-iOS.xcodeproj/xcshareddata/xcschemes/fastbot_stub.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Fastbot-iOS/FastbotRunner/FastbotRunner.m: -------------------------------------------------------------------------------- 1 | 2 | //MIT License 3 | // 4 | //** ** ** 5 | //The Fastbot-iOS is licensed under the MIT License: 6 | // 7 | //Copyright (c) 2021 Bytedance Inc. 8 | // 9 | //Permission is hereby granted, free of charge, to any person obtaining a copy 10 | //of this software and associated documentation files (the "Software"), to deal 11 | //in the Software without restriction, including without limitation the rights 12 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | //copies of the Software, and to permit persons to whom the Software is 14 | //furnished to do so, subject to the following conditions: 15 | // 16 | //The above copyright notice and this permission notice shall be included in all 17 | //copies or substantial portions of the Software. 18 | // 19 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | //SOFTWARE. 26 | 27 | 28 | // FastbotRunner.m 29 | // 30 | // Created by fastbot on 2021/6/6. 31 | // 32 | 33 | #import 34 | #import "fastbot_native.h" 35 | 36 | @interface FastbotRunner : XCTestCase 37 | 38 | @property (nonatomic, assign) BOOL shouldKeepRunning; 39 | @end 40 | 41 | @implementation FastbotRunner 42 | 43 | - (void)setUp { 44 | // Put setup code here. This method is called before the invocation of each test method in the class. 45 | self.shouldKeepRunning = YES; 46 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(exitRunloop) name:@"fastbot-done" object:nil]; 47 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 48 | } 49 | 50 | -(void) testFastbot 51 | { 52 | NSDictionary* startEnv = [[NSProcessInfo processInfo] environment]; 53 | fastbot *fastbot_native = [[Fastbot_native alloc] init:startEnv]; 54 | [fastbot_native start]; 55 | 56 | // @notice you can uncomment this for some custom action when system alerts 57 | // [fastbot_native addUIInterruptionMonitor:^CGRect(NSArray *systemAlerts) { 58 | // NSArray *buttons = [systemAlerts.firstObject.buttons allElementsBoundByIndex]; 59 | // NSInteger buttonCount = [buttons count]; 60 | // CGRect btnRect = CGRectZero; 61 | // if(buttonCount<=0) 62 | // return btnRect; 63 | // if(buttonCount > 2) 64 | // { 65 | // btnRect = [[buttons objectAtIndex:1] frame]; 66 | // } 67 | // else 68 | // btnRect = [buttons.lastObject frame]; 69 | // return btnRect; 70 | // }]; 71 | 72 | [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; 73 | while (self.shouldKeepRunning && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); 74 | } 75 | 76 | 77 | -(void) testPingNetwork 78 | { 79 | int count = 180; 80 | while (count--) { 81 | NSString *getResponeStr = [netclient get:@{} hostport:-1 hostip:@"http://www.bytedance.com" pathStr:@""]; 82 | if(getResponeStr.length > 10) 83 | { 84 | [FBLogger log:@"ping network success"]; 85 | return; 86 | } 87 | [FBLogger log:@"By tapping FastbotRunner on the device, the screen of the device would go black for about one minute. During the black screen interval, users should press the home button on the device to go back to the main screen. Wait patiently until the network setting dialog window pops up. Users should allow the pop up request in order to continue."]; 88 | [NSThread sleepForTimeInterval:1.0]; 89 | } 90 | } 91 | 92 | - (void)tearDown { 93 | // Put teardown code here. This method is called after the invocation of each test method in the class. 94 | } 95 | 96 | - (void)exitRunloop { 97 | self.shouldKeepRunning = NO; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /Fastbot-iOS/FastbotRunner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Fastbot-iOS/Podfile: -------------------------------------------------------------------------------- 1 | #MIT License 2 | # 3 | #** ** ** 4 | #The fastbot SDK is licensed under the MIT License: 5 | # 6 | #Copyright (c) 2021 Bytedance Inc. 7 | # 8 | #Permission is hereby granted, free of charge, to any person obtaining a copy 9 | #of this software and associated documentation files (the "Software"), to deal 10 | #in the Software without restriction, including without limitation the rights 11 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | #copies of the Software, and to permit persons to whom the Software is 13 | #furnished to do so, subject to the following conditions: 14 | # 15 | #The above copyright notice and this permission notice shall be included in all 16 | #copies or substantial portions of the Software. 17 | # 18 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | #SOFTWARE. 25 | 26 | platform :ios, '9.0' 27 | 28 | project 'Fastbot-iOS.xcodeproj' 29 | 30 | target 'FastbotRunner' do 31 | pod 'fastbot', :path => "./", :subspecs => [ 32 | 'fastbot' 33 | ] 34 | end 35 | 36 | 37 | 38 | 39 | target 'fastbot_stub' do 40 | pod "GCDWebServer", "~> 3.0" 41 | pod "fastbot-stub", :path => "./" 42 | end 43 | 44 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot-stub.podspec: -------------------------------------------------------------------------------- 1 | #MIT License 2 | # 3 | #** ** ** 4 | #The fastbot SDK is licensed under the MIT License: 5 | # 6 | #Copyright (c) 2021 Bytedance Inc. 7 | # 8 | #Permission is hereby granted, free of charge, to any person obtaining a copy 9 | #of this software and associated documentation files (the "Software"), to deal 10 | #in the Software without restriction, including without limitation the rights 11 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | #copies of the Software, and to permit persons to whom the Software is 13 | #furnished to do so, subject to the following conditions: 14 | # 15 | #The above copyright notice and this permission notice shall be included in all 16 | #copies or substantial portions of the Software. 17 | # 18 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | #SOFTWARE. 25 | 26 | # 27 | # Any lines starting with a # are optional, but their use is encouraged 28 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 29 | # 30 | 31 | Pod::Spec.new do |s| 32 | s.name = 'fastbot-stub' 33 | s.version = '0.0.1' 34 | s.summary = 'fastbot-stub' 35 | s.homepage = 'https://github.com/bytedance/Fastbot-iOS' 36 | s.license = { :type => 'MIT', :file => '../LICENSE' } 37 | s.author = { 'fastbot' => 'smart-qa@bytedance.com' } 38 | s.source = { :git => 'git@github.com:bytedance/Fastbot_iOS.git', :tag => s.version.to_s } 39 | 40 | s.ios.deployment_target = '9.0' 41 | 42 | s.vendored_frameworks = [] 43 | s.source_files = "fastbot-stub/*.{h,m,mm}" 44 | end 45 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot-stub/stub.h: -------------------------------------------------------------------------------- 1 | //MIT License 2 | // 3 | //** ** ** 4 | //The fastbot SDK is licensed under the MIT License: 5 | // 6 | //Copyright (c) 2021 Bytedance Inc. 7 | // 8 | //Permission is hereby granted, free of charge, to any person obtaining a copy 9 | //of this software and associated documentation files (the "Software"), to deal 10 | //in the Software without restriction, including without limitation the rights 11 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | //copies of the Software, and to permit persons to whom the Software is 13 | //furnished to do so, subject to the following conditions: 14 | // 15 | //The above copyright notice and this permission notice shall be included in all 16 | //copies or substantial portions of the Software. 17 | // 18 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | //SOFTWARE. 25 | 26 | 27 | #import 28 | 29 | // fastbot stub , embed for test app 30 | // very simple sample for stub 31 | @interface FastbotStub : NSObject 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot-stub/stub.m: -------------------------------------------------------------------------------- 1 | //MIT License 2 | // 3 | //** ** ** 4 | //The fastbot SDK is licensed under the MIT License: 5 | // 6 | //Copyright (c) 2021 Bytedance Inc. 7 | // 8 | //Permission is hereby granted, free of charge, to any person obtaining a copy 9 | //of this software and associated documentation files (the "Software"), to deal 10 | //in the Software without restriction, including without limitation the rights 11 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | //copies of the Software, and to permit persons to whom the Software is 13 | //furnished to do so, subject to the following conditions: 14 | // 15 | //The above copyright notice and this permission notice shall be included in all 16 | //copies or substantial portions of the Software. 17 | // 18 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | //SOFTWARE. 25 | 26 | 27 | #import 28 | #import 29 | #import "stub.h" 30 | #import "GCDWebServer.h" 31 | #import "GCDWebServerDataResponse.h" 32 | #import "GCDWebServerDataRequest.h" 33 | 34 | 35 | @interface FastbotStub() 36 | 37 | @property(nonatomic, strong) GCDWebServer* webServer; 38 | 39 | @end 40 | 41 | @implementation FastbotStub 42 | 43 | +(void) load{ 44 | // delay listen fastbot 45 | static dispatch_once_t onceToken; 46 | dispatch_once(&onceToken, ^{ 47 | __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:nil usingBlock:^(NSNotification *note) { 48 | [FastbotStub listenFastbot]; 49 | [[NSNotificationCenter defaultCenter] removeObserver:observer]; 50 | }]; 51 | }); 52 | } 53 | 54 | 55 | static FastbotStub* __fastbotStub = nil; 56 | 57 | +(void) listenFastbot 58 | { 59 | if(__fastbotStub == nil) 60 | { 61 | __fastbotStub = [[FastbotStub alloc] init]; 62 | } 63 | if(__fastbotStub != nil) 64 | { 65 | [__fastbotStub delayListenFastbot]; 66 | } 67 | 68 | } 69 | 70 | -(instancetype)init 71 | { 72 | self = [super init]; 73 | return self; 74 | } 75 | 76 | // describe current App windows 77 | -(NSDictionary*) describePages 78 | { 79 | NSMutableDictionary* pageDesc = [[NSMutableDictionary alloc] init]; 80 | UIApplication* app = [UIApplication sharedApplication]; 81 | NSArray* windows = nil; 82 | if (@available(iOS 13.0, *)) { 83 | NSSet *scenes = [app connectedScenes]; 84 | for(UIScene* scen in scenes) 85 | { 86 | if([scen isKindOfClass:[UIWindowScene class]]) 87 | { 88 | windows = ((UIWindowScene*)scen).windows; 89 | break; 90 | } 91 | } 92 | } else { 93 | windows = [app windows]; 94 | } 95 | NSMutableArray* pages = [[NSMutableArray alloc] init]; 96 | NSArray *sortedWindows = [windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow* w1, UIWindow* w2) { 97 | if([w1 windowLevel] == [w2 windowLevel]) 98 | { 99 | if([w1 isKeyWindow]){ 100 | return -1; 101 | } 102 | if([w2 isKeyWindow]){ 103 | return 1; 104 | } 105 | } 106 | return [w1 windowLevel] < [w2 windowLevel]? 1 : -1; 107 | }]; 108 | for(UIView* view in sortedWindows) 109 | { 110 | [pages addObject:[self describeUIView:view]]; 111 | } 112 | pageDesc[@"desc"] = pages; 113 | return pageDesc; 114 | } 115 | 116 | // describe the UIView, prefer more accurate property, prefer more simplify UIView Struct 117 | -(NSDictionary *) describeUIView:(UIView *)view 118 | { 119 | NSMutableDictionary *viewDesc = [[NSMutableDictionary alloc] init]; 120 | NSMutableDictionary* viewProp = [NSMutableDictionary dictionaryWithDictionary: @{ 121 | @"rect": [self rectUIView:view], 122 | @"type": NSStringFromClass([view class]), 123 | @"identifier": [self nonullNSString:[view accessibilityIdentifier]], 124 | @"visible": @([@(!view.hidden && view.alpha>0.01) boolValue]), 125 | @"interactive": @(view.userInteractionEnabled), 126 | @"value": [self nonullNSString:[view accessibilityValue]], 127 | @"label": [self nonullNSString:[view accessibilityLabel]], 128 | @"scrollable": @([self uiViewScrollable:view]), 129 | @"clickable": @([self uiViewClickable:view]) 130 | }]; 131 | NSString* controller = [self uiViewViewControllerStr:view]; 132 | if( 0 != controller.length) 133 | { 134 | viewProp[@"controller"] = controller; 135 | viewProp[@"vcInheritance"] = [self uiViewVcInhteritChain:view]; 136 | } 137 | viewDesc[@"view"] = viewProp; 138 | NSArray *subviews = view.subviews; 139 | viewDesc[@"children"] = [[NSMutableArray alloc] init]; 140 | if (subviews.count > 0) { 141 | for (UIView *view in subviews) { 142 | [viewDesc[@"children"] addObject:[self describeUIView:view ]]; 143 | } 144 | } 145 | return viewDesc; 146 | } 147 | 148 | // get the UIView's rect 149 | - (NSDictionary *)rectUIView:(UIView*)view{ 150 | CGRect rect; 151 | rect = [view convertRect:view.bounds toCoordinateSpace:[UIScreen mainScreen].coordinateSpace]; 152 | return @{ 153 | @"left":@(round(rect.origin.x)), 154 | @"top":@(round(rect.origin.y)), 155 | @"width":@(round(rect.size.width)), 156 | @"height":@(round(rect.size.height)), 157 | }; 158 | } 159 | 160 | // is the UIView scrollable 161 | -(BOOL) uiViewScrollable:(UIView*)view 162 | { 163 | if([view isKindOfClass:[UIScrollView class]]) 164 | { 165 | return ((UIScrollView*)view).scrollEnabled; 166 | } 167 | return NO; 168 | } 169 | 170 | // is the UIView clickable, prefer a better hitTest 171 | -(BOOL) uiViewClickable:(UIView*)view 172 | { 173 | __block BOOL clickable = NO; 174 | [view.gestureRecognizers enumerateObjectsUsingBlock:^(__kindof UIGestureRecognizer * _Nonnull obj, 175 | NSUInteger idx, BOOL * _Nonnull stop) { 176 | if([obj isKindOfClass:[UITapGestureRecognizer class]]) 177 | { 178 | clickable = YES; 179 | if( stop != NULL) 180 | { 181 | *stop = YES; 182 | } 183 | } 184 | }]; 185 | if(!clickable) 186 | { 187 | CGRect wrect = view.bounds; 188 | wrect = [view.window convertRect:wrect toView:view]; 189 | CGPoint centerPoint = CGPointMake(CGRectGetMidX(wrect), CGRectGetMidY(wrect)); 190 | UIView* hitestView = [view.window hitTest:centerPoint withEvent:nil]; 191 | clickable = hitestView && ([hitestView isKindOfClass:[UIControl class]] && [view isDescendantOfView:hitestView]); 192 | clickable = clickable || (hitestView && [hitestView isDescendantOfView:view]); 193 | } 194 | 195 | return clickable; 196 | } 197 | 198 | // ViewController of the UIView 199 | -(NSString*) uiViewViewControllerStr:(UIView*)view 200 | { 201 | id viewController = [self uiViewViewController: view]; 202 | return viewController? NSStringFromClass([viewController class]) : @""; 203 | } 204 | 205 | -(id) uiViewViewController:(UIView*)view { 206 | id responder = [view nextResponder]; 207 | if ([responder isKindOfClass: [UIViewController class]] && 208 | ((UIViewController *)responder).view.window && 209 | ((UIViewController *)responder).isViewLoaded ) { 210 | return responder; 211 | } 212 | return nil; 213 | } 214 | 215 | // Inherit ViewControllers of the UIView 216 | -(NSArray*) uiViewVcInhteritChain:(UIView*)view 217 | { 218 | NSMutableArray *vcInheritanceChain = [NSMutableArray array]; 219 | id responder = [self uiViewViewController:view]; 220 | if(responder && 221 | [responder isKindOfClass:[UIViewController class]] && 222 | ((UIViewController *)responder).view.window && 223 | ((UIViewController *)responder).isViewLoaded ) 224 | { 225 | Class respnderclzz = [responder class]; 226 | while([UIViewController class] != respnderclzz) { 227 | [vcInheritanceChain addObject:NSStringFromClass(respnderclzz)]; 228 | respnderclzz = [respnderclzz superclass]; 229 | } 230 | } 231 | return vcInheritanceChain; 232 | } 233 | 234 | -(NSString*) nonullNSString:(nullable NSString*) str 235 | { 236 | return str? str : @""; 237 | } 238 | 239 | -(BOOL) delayListenFastbot 240 | { 241 | if(self.webServer == nil) 242 | { 243 | _webServer = [[GCDWebServer alloc] init]; 244 | } 245 | if(self.webServer.isRunning) 246 | { 247 | [self.webServer stop]; 248 | } 249 | __weak typeof(self) weakSelf = self; 250 | [self.webServer addHandlerForMethod:@"POST" path:@"/view" requestClass:[GCDWebServerDataRequest class] 251 | asyncProcessBlock:^(__kindof GCDWebServerRequest * _Nonnull request, GCDWebServerCompletionBlock _Nonnull completionBlock) { 252 | GCDWebServerDataRequest *datarequest = (GCDWebServerDataRequest *)request; 253 | NSDictionary* data = datarequest.jsonObject; 254 | NSLog(@"receive request path = %@, %@, %@", request.URL, request.path, request.contentType); 255 | NSLog(@"request body data %@", data); 256 | __block GCDWebServerDataResponse* response = nil; 257 | dispatch_async(dispatch_get_main_queue(), ^{ 258 | NSDictionary* viewDict = [[NSMutableDictionary alloc] init]; 259 | @try { 260 | viewDict = [weakSelf describePages]; 261 | } 262 | @catch(NSException *exception) 263 | { 264 | NSLog(@"Describe page Erorr!!! %@", exception.description); 265 | } 266 | response = [GCDWebServerDataResponse responseWithJSONObject:viewDict]; 267 | completionBlock(response); 268 | }); 269 | }]; 270 | 271 | NSTimeInterval delay = 2.0; 272 | dispatch_queue_t lfqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 273 | dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)); 274 | dispatch_after(delayTime, lfqueue, ^(void){ 275 | NSDictionary* startEnv = [[NSProcessInfo processInfo] environment]; 276 | NSString* stubPortStr = [startEnv objectForKey:@"stubPort"]; 277 | #ifdef DEBUG 278 | if(stubPortStr == nil) 279 | stubPortStr = @"9797"; 280 | #endif 281 | if(stubPortStr != nil && stubPortStr.length > 0) 282 | { 283 | NSInteger stubPort = [stubPortStr integerValue]; 284 | if(stubPort > 0) 285 | { 286 | NSMutableDictionary* options = [NSMutableDictionary dictionary]; 287 | [options setObject:[NSNumber numberWithInteger:stubPort] forKey:GCDWebServerOption_Port]; 288 | [options setObject:@(NO) forKey:GCDWebServerOption_AutomaticallySuspendInBackground]; 289 | NSError* err = nil; 290 | [weakSelf.webServer startWithOptions:options error:&err]; 291 | if(err == nil) 292 | { 293 | NSLog(@"start fastbot listen success!"); 294 | } 295 | } 296 | } 297 | }); 298 | return TRUE; 299 | } 300 | 301 | @end 302 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot.podspec: -------------------------------------------------------------------------------- 1 | #MIT License 2 | # 3 | #** ** ** 4 | #The fastbot SDK is licensed under the MIT License: 5 | # 6 | #Copyright (c) 2021 Bytedance Inc. 7 | # 8 | #Permission is hereby granted, free of charge, to any person obtaining a copy 9 | #of this software and associated documentation files (the "Software"), to deal 10 | #in the Software without restriction, including without limitation the rights 11 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | #copies of the Software, and to permit persons to whom the Software is 13 | #furnished to do so, subject to the following conditions: 14 | # 15 | #The above copyright notice and this permission notice shall be included in all 16 | #copies or substantial portions of the Software. 17 | # 18 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | #SOFTWARE. 25 | 26 | # 27 | # Any lines starting with a # are optional, but their use is encouraged 28 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 29 | # 30 | 31 | Pod::Spec.new do |s| 32 | s.name = 'fastbot' 33 | s.version = '0.2.0' 34 | s.summary = 'Fastbot-iOS' 35 | s.homepage = 'https://github.com/bytedance/Fastbot-iOS' 36 | s.license = { :type => 'MIT', :file => '../LICENSE' } 37 | s.author = { 'fastbot' => 'smart-qa@bytedance.com' } 38 | s.source = { :git => 'git@github.com:bytedance/Fastbot_iOS.git', :tag => s.version.to_s } 39 | 40 | s.ios.deployment_target = '9.0' 41 | s.osx.deployment_target = '10.13' 42 | 43 | s.xcconfig = { 'SYSTEM_FRAMEWORK_SEARCH_PATHS' => '"$(PLATFORM_DIR)/Developer/Library/PrivateFrameworks" "$(PLATFORM_DIR)/Developer/Library/Frameworks"', 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2' } 44 | 45 | s.frameworks = 'XCTest' 46 | s.libraries = ['xml2.2'] 47 | 48 | 49 | s.subspec 'fastbot' do |ss| 50 | ss.vendored_frameworks = ["fastbot/fastbot_native.framework","fastbot/fastbot_cv.framework","fastbot/FastbotLib.framework"] 51 | ss.source_files = "fastbot/Headers/*.{h}" 52 | ss.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) FASTBOT_NATIVE=1' } 53 | end 54 | 55 | 56 | s.subspec 'fastbot-stub' do |ss| 57 | ss.vendored_frameworks = ['XCTest'] 58 | ss.source_files = "fastbot-stub/*.{h,m,mm}" 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/FastbotLib.framework/FastbotLib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Fastbot-iOS/fastbot/FastbotLib.framework/FastbotLib -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/FastbotLib.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Fastbot-iOS/fastbot/FastbotLib.framework/Info.plist -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/Headers/fastbot_native.h: -------------------------------------------------------------------------------- 1 | //MIT License 2 | // 3 | //** ** ** 4 | //The fastbot SDK is licensed under the MIT License: 5 | // 6 | //Copyright (c) 2021 Bytedance Inc. 7 | // 8 | //Permission is hereby granted, free of charge, to any person obtaining a copy 9 | //of this software and associated documentation files (the "Software"), to deal 10 | //in the Software without restriction, including without limitation the rights 11 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | //copies of the Software, and to permit persons to whom the Software is 13 | //furnished to do so, subject to the following conditions: 14 | // 15 | //The above copyright notice and this permission notice shall be included in all 16 | //copies or substantial portions of the Software. 17 | // 18 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | //SOFTWARE. 25 | 26 | 27 | #import 28 | 29 | @protocol UIAppDelegate 30 | @end 31 | 32 | @protocol CommandDelegate 33 | @end 34 | 35 | // fastbot 36 | @interface fastbot: NSObject 37 | 38 | - (id) init; 39 | 40 | - (id) init:(NSDictionary*) envParam; 41 | 42 | - (void) start; 43 | 44 | - (void)addUIInterruptionMonitor:(CGRect (^)(NSArray *systemAlerts))handler; 45 | 46 | @end 47 | 48 | // fastbot native 49 | @interface Fastbot_native: fastbot 50 | 51 | @end 52 | 53 | // fastbot logger 54 | @interface FBLogger : NSObject 55 | + (void)log:(NSString *)message; 56 | + (void)logFmt:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2); 57 | @end 58 | 59 | // fastbot netclient 60 | @interface netclient : NSObject 61 | +(NSString*)get:(NSDictionary*)param hostport:(int)hostport hostip:(NSString*)hostip pathStr:(NSString*)pathStr; 62 | @end 63 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_cv.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Fastbot-iOS/fastbot/fastbot_cv.framework/Info.plist -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_cv.framework/fastbot_cv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Fastbot-iOS/fastbot/fastbot_cv.framework/fastbot_cv -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_cv.framework/fastbot_cv.bundle/config/appconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_cv.framework/fastbot_cv.bundle/config/default.jsonsetting: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1.0, 3 | "date": "02/13/2020", 4 | "ocr":true, 5 | "events": [ 6 | { 7 | "type": "event", 8 | "name": "eventbase", 9 | "require":[], 10 | "exclude":[], 11 | "actions":[], 12 | "roi":[], 13 | "rate":1.0 14 | } 15 | ], 16 | "actions":[ 17 | { 18 | "type": "xaction", 19 | "name":"restart", 20 | "cmd":"RESTART", 21 | "duration": 1.0 22 | }, 23 | { 24 | "type": "xaction", 25 | "name":"terminate", 26 | "cmd":"TERMINATE", 27 | "duration": 1.0 28 | }, 29 | { 30 | "type": "xaction", 31 | "name":"start", 32 | "cmd":"START", 33 | "duration": 1.0 34 | }, 35 | { 36 | "type": "xaction", 37 | "name":"home", 38 | "cmd":"HOME", 39 | "duration": 1.0 40 | }, 41 | { 42 | "type": "xaction", 43 | "name": "back", 44 | "descrition": "back 特殊指令,执行返回操作", 45 | "cmd":"BACK", 46 | "text":"", 47 | "duration": 1.0 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_cv.framework/fastbot_cv.bundle/config/default.setting: -------------------------------------------------------------------------------- 1 | preference version02132020 2 | { 3 | version = 1.0 4 | date = 02/13/2020 5 | 6 | //// 支持 1 种类型 event 7 | group events 8 | { 9 | 10 | } 11 | 12 | // 已支持 5 种类型 action, posaction, noaction, xaction, maction 13 | group actions 14 | { 15 | } 16 | 17 | group sequence 18 | { 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_cv.framework/fastbot_cv.bundle/config/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "channel":"OS" 3 | } -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_cv.framework/fastbot_cv.bundle/config/testconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "SkipCheckBlock":false, 3 | "SkipRestart":false, 4 | "SkipHome":false 5 | } 6 | 7 | -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_native.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Fastbot-iOS/fastbot/fastbot_native.framework/Info.plist -------------------------------------------------------------------------------- /Fastbot-iOS/fastbot/fastbot_native.framework/fastbot_native: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytedance/Fastbot_iOS/cf58560f0439bb1be4759dbb031d1332d269e7b8/Fastbot-iOS/fastbot/fastbot_native.framework/fastbot_native -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Fastbot Revised License 2 | 3 | Effective from Jan 1st, 2022, The Fastbot SDK is hereby licensed as follows: 4 |   5 | Copyright (c) 2020-2022 Bytedance Inc. (The “Licensor”) 6 | The Licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below (“Rights and Limitations”): 7 | 8 | You may not provide or distribute the software to third parties. You may use it solely for your own internal use. “Internal use” permits distribution to your affiliates and to contractors where those contractors are permitted to exercise the Rights and Limitations solely on your and your affiliates’ 9 | behalf. An “affiliate” is an entity that controls, is controlled by, or is under common control with you. For the purposes of this definition "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty 10 | percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 11 |   12 | You may not alter, remove, or obscure any licensing, copyright, or other notices of the Licensor in the software. Any use of the Licensor's trademarks is prohibited unless otherwise permitted by applicable law. 13 |   14 | This License will terminate immediately without notice should you breach any term. 15 |   16 | TO THE EXTENT THAT SUCH EXCLUSION IS PERMITTED BY LAW, (1)THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF SATISFACTORY QUALITY, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT, AND (2) IN NO EVENT SHALL THE LICENSOR, AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | Fastbot is a model-based testing tool for modeling GUI transitions to discover app stability problems. It combines machine learning and reinforcement learning techniques to assist discovery in a more intelligent way. 3 | > Related: [Fastbot_Android](https://github.com/bytedance/Fastbot_Android) 4 | 5 | ***More detail see at [Fastbot architecture](https://mp.weixin.qq.com/s/QhzqBFZygkIS6C69__smyQ) 6 | 7 | **update 2022.1** 8 | * update Fastbot Revised License 9 | * release AnyTrace, the Fastbot test management assistant: supports one-click Fastbot test start, crash analysis, etc. ([AnyTrace User Manual](https://www.volcengine.com/docs/6431/82895)) 10 | 11 | 12 | ## Prepare test environment 13 | * `cd Fastbot-iOS && pod install --repo-update` 14 | * Open `Fastbot-iOS.xcworkspace`, Set `FastbotRunner` [Signing & Capabilities](./Doc/Fastbot-Xcode-Sign.png) and [Bundle ID](./Doc/Fastbot-Xcode-BundleId.png) 15 | * USB connected the device & trust the device, if you're using a simulator, start up the simulator 16 | * Open FastbotRunner network permission (unnecessary for simulator), a sample on device 00008030-001054A80C82802E: 17 | * - Open [XcodeIDE run `testPingNetwork` in Tests](./Doc/Fastbot-Xcode-IDE.png) or Run command: 18 | ```shell 19 | BUNDLEID=com.apple.Pages duration=240 throttle=300 xcodebuild test -workspace Fastbot-iOS.xcworkspace -scheme FastbotRunner -configuration Release -destination 'platform=iOS,id=00008030-001804563E44802E' -only-testing:FastbotRunner/FastbotRunner/testPingNetwork 20 | ``` 21 | * - By tapping FastbotRunner on the device, the screen of the device would go black for about one minute. During the black screen interval, users should press the home button on the device to go back to the main screen. Wait patiently until the network setting dialog window pops up. Users should allow the pop up request in order to continue. 22 | * - If "`ping network success`" appears in the console log, that means get network permission **successful** 23 | 24 | ## Run Test 25 | * Ensure that your application can run on the device. (Installed and trusted) 26 | * Environment Variables should be setted in command line or [Xcode IDE/Scheme/Test](./Doc/Fastbot-Xcode-Scheme.png) 27 | 28 | |key|note|sample| 29 | |--|--|--| 30 | | BUNDLEID| Test App's Bundle ID|com.apple.Pages 31 | |duration|Test duration, units of minutes|300 32 | |launchenv|Start arguments for Test APP, can be empty or key-values separated with ":" |isAutoTestUI=1:channel=AutoTest 33 | |throttle|Throttle for operate, units of millisecond|300 34 | 35 | * A sample run test on device 00008030-001054A80C82802E. *if IDE scheme Env Vars changed , command Env Var would be void*: 36 | ```shell 37 | BUNDLEID=com.apple.Pages duration=240 throttle=300 xcodebuild test -workspace Fastbot-iOS.xcworkspace -scheme FastbotRunner -configuration Release -destination 'platform=iOS,id=00008030-001804563E44802E' -only-testing:FastbotRunner/FastbotRunner/testFastbot 38 | ``` 39 | 40 | ***More detail see at [中文手册](./Doc/handbook-cn.md)*** 41 | 42 | 43 | ----------- 44 | ## Advanced Extension 45 | Stub mode: Target dynamic library [`fastbot_stub`](./Fastbot-iOS/fastbot-stub/stub.m). Stub mode requires injection of fastbot_stub into the test app. The library captures GUI structure by parsing the app under test for fastbot. More customized features (eg. hook callback, cut View) can be constructed by users for additional abilities such as blocking certain view from being clicked, customized ViewControllers, etc. 46 | 47 | *We highly appreciate any contribution from the community !!!* 48 | 49 | **Usage**: 50 | After injecting fastbot_stub to app, you need: 51 | * Uncomment code block `[fastbot_native addUIInterruptionMonitor: ...];` in [FastbotRunner.m](./Fastbot-iOS/FastbotRunner/FastbotRunner.m#L57) 52 | * Run the stub mode by editing [Scheme Environment Variables](./Doc/Fastbot-Xcode-Scheme.png)(9797 can be changed to another port number): 53 | 54 | |key|sample| 55 | |--|--| 56 | |launchenv|stubPort=9797 57 | |dataport|9797 58 | 59 | ----------- 60 | ## Analytics 61 | 62 | To prioritize and improve Fastbot-iOS, FastbotRunner collects usage data and uploads it to Google Analytics. FastbotRunner collects the md5 hash of the test app's Bundle ID, this information allows us to measure the volume of usage. If they wish, users can choose to disable the Analytics by skip step `Open FastbotRunner network permission` or change FastbotRunner's `Wireless Data` to off in System Preference. 63 | 64 | ----------- 65 | ## Support 66 | * Public technical discussion on github is preferred. 67 | * Q&A: 68 | 69 | **Q**: Get Error when `pod install --repo-update`
70 | **A**: install pod firstly `sudo gem install cocoapods -v=1.8.1` 71 |
72 | 73 | **Q**: Get Error: `Assert Fail Timed out while evaluating UI query`
74 | **A**: Restart test or Replug USB or Change a USB line or Restart iPhone 75 |
76 | 77 | **Q**: Get Error when use simulator
78 | **A**: Change to Debug Mode in scheme setting 79 |
80 | 81 | 82 | **Q**: Get unkown install Error:`com.apple.dt.MobileDeviceErrorDomain`
83 | **A**: Check your signing certificate or Replug USB or Change a USB line or Restart iPhone 84 |
85 | 86 | -------- 87 | ## License 88 | > Copyright©2021 Bytedance 89 | > 90 | > Licensed under [Fastbot Revised](./LICENSE) 91 | 92 | Fastbot-iOS required some features are based on or derives from projects below: 93 | * [WebDriverAgent](https://github.com/facebook/WebDriverAgent) licensed under BSD-3-Clause 94 | 95 | 96 | ## Publications 97 | 98 | If you use our work in your research, please kindly cite us as: 99 | 100 | 1. Lv, Zhengwei, Chao Peng, Zhao Zhang, Ting Su, Kai Liu, Ping Yang (2022). “Fastbot2: Reusable Automated Model-based GUI Testing for Android Enhanced by Reinforcement Learning”. In proceedings of the 37th IEEE/ACM International Conference on Automated Software Engineering (ASE 2022). ACM, To appear. [[pdf]](https://se-research.bytedance.com/pdf/ASE22.pdf) 101 | 102 | ```bibtex 103 | @inproceedings{fastbot2, 104 | title={Fastbot2: Reusable Automated Model-based GUI Testing for Android Enhanced by Reinforcement Learning}, 105 | author={Lv, Zhengwei and Peng, Chao and Zhang, Zhao and Su, Ting and Liu, Kai and Yang, Ping}, 106 | booktitle={Proceedings of the 37th IEEE/ACM International Conference on Automated Software Engineering (ASE 2022)}, 107 | year={2022} 108 | } 109 | ``` 110 | 111 | 2. Peng, Chao, Zhao Zhang, Zhengwei Lv, Ping Yang (2022). “MUBot: Learning to Test Large-Scale Commercial Android Apps like a Human”. In proceedings of the 38th International Conference on Software Maintenance and Evolution (ICSME 2022). IEEE, To appear. [[pdf]](https://se-research.bytedance.com/pdf/ICSME22B.pdf) 112 | 113 | ```bibtex 114 | @inproceedings{mubot, 115 | title={MUBot: Learning to Test Large-Scale Commercial Android Apps like a Human}, 116 | author={Peng, Chao and Zhang, Zhao and Lv, Zhengwei and Yang, Ping}, 117 | booktitle={Proceedings of the 38th International Conference on Software Maintenance and Evolution (ICSME 2022)}, 118 | year={2022} 119 | } 120 | ``` 121 | 122 | 3. Cai, Tianqin, Zhao Zhang, and Ping Yang. “Fastbot: A Multi-Agent Model-Based Test Generation System”. In Proceedings of the IEEE/ACM 1st International Conference on Automation of Software Test. 2020. [[pdf]](https://se-research.bytedance.com/pdf/AST20.pdf) 123 | 124 | ```bibtex 125 | @inproceedings{fastbot, 126 | title={Fastbot: A Multi-Agent Model-Based Test Generation System}, 127 | author={Cai, Tianqin and Zhang, Zhao and Yang, Ping}, 128 | booktitle={Proceedings of the IEEE/ACM 1st International Conference on Automation of Software Test}, 129 | pages={93--96}, 130 | year={2020} 131 | } 132 | ``` --------------------------------------------------------------------------------