## Appium XCUITest Driver 真機設置
### 安裝依賴
從 1.15.0 版本開始,Appium 通過 [appium-ios-device](https://github.com/appium/appium-ios-device) 和真機交互。
已經不需要安裝額外的依賴。
XCUITest driver 會在設備上安裝一個名為 `WebDriverAgent-Runner` 的輔助應用,然后通過它操縱待測應用。
雖然理論上簡單,但處理簽名和 provisioning 讓開發和測試變得有點兒麻煩。
Xcode 需要能訪問這個設備。請通過 _設備 或 _模擬器 的 Xcode 日志確保測試用的設備可以正常連接到 Xcode。
[appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver) 的文檔也有助于處理依賴。
### 基礎 (自動) 配置
在 iOS 真機上支持 Appium XCUITest 運行的最簡單的方法是使用自動配置策略。有兩種做法:
* 使用 `xcodeOrgId` 和 `xcodeSigningId` desired capabilities:
```json
{
"xcodeOrgId": "<Team ID>",
"xcodeSigningId": "iPhone Developer"
}
```
* 新建一個 `.xcconfig` 文件,添加如下內容:
```
DEVELOPMENT_TEAM = <Team ID>
CODE_SIGN_IDENTITY = iPhone Developer
```
不論哪種做法,Team ID 是蘋果生成后分配給你團隊的一個唯一的 10 位字符串。用開發者賬號可以找到你的 Team ID。
登錄 [developer.apple.com/account](http://developer.apple.com/account),在邊欄點擊 Membership。
你的 Team ID 在 Membership Information 分節的 team name 下面。在“鑰匙串訪問”,你的 iPhone Developer
證書的“組織單位”的值也是 Team ID。
注意這兩個做法互斥,使用 `xcodeConfigFile` capability 或者 `xcodeOrgId` 和 `xcodeSigningId`
組合的其中一個。
配置完成后,應該只需要給 `udid` desired capability 指定一個真機就可以開始測試了。
如果沒有正常運行,通常會在 Appium server 日志中列出一些錯誤和`info XCUITest xcodebuild exited with code '65' and signal 'null'`。這通常是因為沒有正確設置代碼簽名。接著可以通過 [基礎 (手動) 配置](#basic-manual-configuration) 來修正。
如果真機上成功安裝了 `WebDriverAgentRunner`,但是 Appium 日志有這樣的錯誤信息:
```
2017-01-24 09:02:18.358 xcodebuild[30385:339674] Error Domain=com.apple.platform.iphoneos Code=-12 "Unable to launch com.apple.test.WebDriverAgentRunner-Runner" UserInfo={NSLocalizedDescription=Unable to launch com.apple.test.WebDriverAgentRunner-Runner, NSUnderlyingError=0x7fa839cadc60 {Error Domain=DTXMessage Code=1 "(null)" UserInfo={DTXExceptionKey=The operation couldn’t be completed. Unable to launch com.apple.test.WebDriverAgentRunner-Runner because it has an invalid code signature, inadequate entitlements or its profile has not been explicitly trusted by the user. : Failed to launch process with bundle identifier 'com.apple.test.WebDriverAgentRunner-Runner'}}}
2017-01-24 09:02:18.358 xcodebuild[30385:339674] Error Domain=IDETestOperationsObserverErrorDomain Code=5 "Early unexpected exit, operation never finished bootstrapping - no restart will be attempted" UserInfo={NSLocalizedDescription=Early unexpected exit, operation never finished bootstrapping - no restart will be attempted}
Testing failed:
Test target WebDriverAgentRunner encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted)
```
這是因為開發者沒有在設備上被信任,嘗試在設備上手動運行 `WebDriverAgentRunner` 應用,
會彈出一條消息:

在設備的 設置 => 通用 => 設備管理 里信任開發者以允許使用 `WebDriverAgentRunner` 應用。
(查看 [蘋果文檔獲取更多信息](https://support.apple.com/en-us/HT204460))。
### 基礎(手動)配置
很多情況下用基礎自動配置還不夠。為了在真機上運行測試一般還需要處理項目的簽名和配置。一般在使用免費開發者賬號
的時會出現這種情況,因為既不能創建通配符 provisioning profile,也不會給默認應用包創建。
會有這種報錯 Xcode **failed to create provisioning profile**

簡單的處理方法是打開 [Xcode](https://developer.apple.com/xcode/) 新建一個項目并創建
provisioning profile:

"iOS" 下的什么類型都行。最簡單的是 "Single View Application":

重要的是使用唯一的 "Product Name" 和 "Organization Name"。還有選擇你的 "Team"。

在 "Project" 標簽里可以確認 provisioning profile 有沒有創建。

也可以在賬戶設置查看 provisioning profile:

現在就有有效的 provisioning profile 了。把 bundle id 填在你測試項目的 `updatedWDABundleId` desired
capability 里。然后再按照 [initial instructions for automatic configuration](#basic-automatic-configuration) 做。
### 全手動配置
也可以手動關聯項目和 provisioning profile(請記得每次升級 WebDriverAgent 以及安裝 Appium
新版本之后都需要重新配置一遍,不建議用這種方式):
* 查找 Appium 安裝在哪里:
```
$ which appium
/path/where/installed/bin/appium
```
* 如果路徑是 `/path/where/installed/bin/appium`,`WebDriverAgent` 項目會在 `/path/where/installed/lib/node_modules/appium/node_modules/appium-webdriveragent`。
在終端進入這個路徑,執行以下命令完成項目設置:
```
mkdir -p Resources/WebDriverAgent.bundle
./Scripts/bootstrap.sh -d
```
* 用 Xcode 打開 `WebDriverAgent.xcodeproj`,分別在 `WebDriverAgentLib` 和 `WebDriverAgentRunner`
targets 的 "General" 選項卡里勾選 "Automatically manage signing",并選上你的 `Development Team`。
然后會自動選上 `Signing Ceritificate`。看起來應該如下圖:

* Xcode 給 `WebDriverAgentRunner` 創建 provisioning profile 的時候可能會失敗:

* 需要手動在 "Build Settings" 選項卡修改 target 的 bundle id,并且把 "Product Bundle Identifier"
從 `com.facebook.WebDriverAgentRunner` 改為 Xcode 可以通過的內容:

* 回到 "General" 選項卡的 `WebDriverAgentRunner` target,現在應該看到它創建了
provisioning profile 并且一切正常:

* 最后,驗證下是否可以正常運行。編譯項目:
```
xcodebuild -project WebDriverAgent.xcodeproj -scheme WebDriverAgentRunner -destination 'id=<udid>' test
```
如果編譯成功,應該輸出如下內容:
```
Test Suite 'All tests' started at 2017-01-23 15:49:12.585
Test Suite 'WebDriverAgentRunner.xctest' started at 2017-01-23 15:49:12.586
Test Suite 'UITestingUITests' started at 2017-01-23 15:49:12.587
Test Case '-[UITestingUITests testRunner]' started.
t = 0.00s Start Test at 2017-01-23 15:49:12.588
t = 0.00s Set Up
```
* 為了完全驗證,可以嘗試訪問 WebDriverAgent 服務狀態(**注意:** 你必須和設備在同一個網絡,
并且知道設備的 IP 地址,可以在 設置 => Wi-Fi => 連接中的網絡 查看):
```
export DEVICE_URL='http://<device IP>:8100'
export JSON_HEADER='-H "Content-Type: application/json;charset=UTF-8, accept: application/json"'
curl -X GET $JSON_HEADER $DEVICE_URL/status
```
應該看到輸出如下返回:
```
{
"value" : {
"state" : "success",
"os" : {
"name" : "iOS",
"version" : "10.2"
},
"ios" : {
"simulatorVersion" : "10.2",
"ip" : "192.168.0.7"
},
"build" : {
"time" : "Jan 23 2017 14:59:57"
}
},
"sessionId" : "8951A6DD-F3AD-410E-A5DB-D042F42F68A7",
"status" : 0
}
```
### 配置待測 App
除了 WebDriverAgent,為了在設備上運行,你的 App 也需要配置好。主要要求是一樣的:用開發
provisioning profile build 的 App(`.ipa` 文件)。[這里](https://medium.com/ios-os-x-development/ios-code-signing-provisioning-in-a-nutshell-d5b247760bef#.5hirl92tn)有一個不錯的流程概述,還有
[這里](https://www.nodesagency.com/understanding-code-signing-for-ios-apps)。
再詳細的說,為了使用真機,你需要:
* [Apple Developer ID](https://developer.apple.com/programs/ios/) 和配置好開發者證書
和 provisioning profile 的有效的開發者賬號。
* 在真機上測試有效的 iOS 開發證書和 Provisioning Profile 是必要的。你的 App 也需要被簽名。在 [Apple documentation](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/TestingYouriOSApp/TestingYouriOSApp.html) 可以找到相關信息。
* 一個配置好可以在 Xcode 里開發用的 iPad 或者 iPhone。
* 一個簽過名的 `.app` 或者 `.ipa` 文件,或者從源碼 build 一個。
* 一臺有 [Xcode](https://developer.apple.com/xcode/) 和 Xcode Command Line Developer Tools
的 Mac。
Appium 用 `ideviceinstaller` (作為 `libimobiledevice` 的一部分被安裝) 把應用安裝到設備上。
不過有時候預先用 Xcode 安裝 App 會更容易確認有沒有問題(再看看 [Apple documentation](https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/TestingYouriOSApp/TestingYouriOSApp.html)。
### 排障方法
1. 通過 Xcode 的 Organizer 或者 iTunes 確認 UDID 是否正確。UDID 是一長串字符(20 個字符以上)。
2. 確認你的測試可以在模擬器上執行。
3. 確認以下設置在你的設備上是**啟用**的:
1. 設置 -> 開發者 -> **Enable UI Automation**
2. 設置 -> Safari 瀏覽器 -> 高級 -> **網頁檢查器** 和 **遠程自動化**
1. 請閱讀 [Automating mobile web apps](/writing-running-appium/web/mobile-web) 了解更多關于 WebView 的細節。
4. 如果你不想為了手工配置生成使用通配符的 provisioning profile ,可以考慮使用 `.xctrunner` 作為 identifier。從 Xcode 11 開始支持了 `.xctrunner` 配置,[參考](https://github.com/appium/appium/issues/13610)。
5. 確認設備沒有越獄
- 設備上管理應用的服務 `com.apple.mobile.installation_proxy` 會[無法工作](https://github.com/appium/appium-desktop/issues/1447)。
- 關于TesterHome和MTSC
- 關于Appium
- 簡介
- Appium 客戶端
- 入門指南
- 已支持的平臺
- API 文檔
- Appium驅動
- XCUITest (iOS)
- XCUITest Real Devices (iOS)
- UIAutomation (iOS)
- UIAutomation Safari Launcher (iOS)
- UIAutomator (Android)
- UIAutomator2 (Android)
- Espresso (Android)
- Windows
- Mac
- Appium命令
- Status
- Execute Mobile Command
- Session
- Create
- End
- Get Session Capabilities
- Go Back
- Screenshot
- Source
- Timeouts
- Timeouts
- Implicit Wait
- Async Script
- Orientation
- Get Orientation
- Set Orientation
- Geolocation
- Get Geolocation
- Set Geolocation
- Logs
- Get Log Types
- Get Logs
- Events
- Log event
- Get events
- Settings
- Update Settings
- Get Device Settings
- Settings
- Update Settings
- Get Device Settings
- Execute Driver Script
- Device
- Activity
- Start Activity
- Current Activity
- Current Package
- App
- Install App
- Is App Installed
- Launch App
- Background App
- Close App
- Reset App
- Remove App
- Activate App
- Terminate App
- Get App State
- Get App Strings
- End Test Coverage
- Clipboard
- Get Clipboard
- Set Clipboard
- Emulator
- Power AC
- Power Capacity
- Files
- Push File
- Pull File
- Pull Folder
- Interactions
- Shake
- Lock
- Unlock
- Is Locked
- Rotate
- Keys
- Press keycode
- Long press keycode
- Hide Keyboard
- Is Keyboard Shown
- Network
- Toggle Airplane Mode
- Toggle Data
- Toggle WiFi
- Toggle Location Services
- Send SMS
- GSM Call
- GSM Signal
- GSM Voice
- Network Speed
- Performance Data
- Get Performance Data
- Performance Data Types
- Screen Recording
- Start Screen Recording
- Stop Screen Recording
- Simulator
- Perform Touch ID
- Toggle Touch ID Enrollment
- System
- Open Notifications
- System Bars
- System Time
- Display density
- Authentication
- Finger Print
- Element
- Find Element
- Find Elements
- Actions
- Click
- Send Keys
- Clear
- Attributes
- Text
- Name
- Attribute
- Selected
- Enabled
- Displayed
- Location
- Size
- Rect
- CSS Property
- Location in View
- Other
- Submit
- Active Element
- Equals Element
- Context
- Get Context
- Get All Contexts
- Set Context
- Interactions
- Mouse
- Move To
- Click
- Double Click
- Button Down
- Button Up
- Touch
- Single Tap
- Double Tap
- Move
- Touch Down
- Touch Up
- Long Press
- Scroll
- Flick
- Multi Touch Perform
- Touch Perform
- W3C Actions
- Web
- Window
- Set Window
- Close Window
- Get Handle
- Get Handles
- Get Title
- Get Window Size
- Set Window Size
- Get Window Position
- Set Window Position
- Maximize Window
- Navigation
- Go to URL
- Get URL
- Back
- Forward
- Refresh
- Storage
- Get All Cookies
- Set Cookie
- Delete Cookie
- Delete All Cookies
- Frame
- Switch to Frame
- Switch to Parent Frame
- Execute Async
- Execute
- 編寫 & 運行Appium腳本
- Running Tests
- Desired Capabilities
- The --default-capabilities flag
- Finding Elements
- Touch Actions
- CLI Arguments
- Server Security
- Web/Web Views
- Mobile Web Testing
- Automating Hybrid Apps
- Using ios-webkit-debug-proxy
- Using Chromedriver
- Image Comparison
- iOS
- Low-Level Insights on iOS Input Events
- XCUITest Mobile Gestures
- XCUITest Mobile App Management
- iOS Pasteboard Guide
- iOS Predicate Guide
- iOS Touch ID Guide
- iOS Install Certificate
- tvOS support
- Pushing/Pulling files
- Audio Capture
- Android
- Low-Level Insights on Android Input Events
- UiSelector Guide
- Espresso Datamatcher Guide
- Android Code Coverage Guide
- Activities Startup Troubleshooting Guide
- How To Execute Shell Commands On The Remote Device
- Android Device Screen Streaming
- How To Emulate IME Actions Generation
- How To Test Android App Bundle
- Other
- Reset Strategies
- Network Connection Guide
- Using Unicode with Appium
- Troubleshooting
- Tutorial
- Swipe Tutorial
- Screen
- Element
- Partial screen
- Simple
- Multiple scroll views
- Add scroll layout
- Tricks and Tips
- Screen
- Element
- Element search
- Fast
- Slow
- Guide
- 進階概念
- 定位圖像中的元素
- 使用定位元素的插件
- 遷移到 XCUITest
- 在 Appium 中使用 Selenium Grid
- Appium Logs Filtering
- 跨域 iframes
- 使用自定義 WDA 服務器
- 使用不同版本的 Xcode 運行
- The Event Timings API
- 并行測試的設置
- The Settings API
- Memory Collection
- 向Appium項目做貢獻
- 從源代碼運行 Appium
- 開發者概述
- 標準開發命令
- Appium 風格指南
- 如何編寫文檔
- Appium 包結構
- 鳴謝