You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS模拟器中为应用授予追踪权限的集成测试方案

iOS模拟器中「用户追踪」权限的官方方法与替代方案

官方方法现状

在iOS 16.2版本的iPhone 14 Pro模拟器中,苹果目前没有专门的官方命令直接管控「用户追踪」(ATT,App Tracking Transparency)权限。常用的xcrun simctl privacy命令(包括grant all参数)对该权限不生效,执行后应用仍会弹出权限请求弹窗。这是因为ATT权限的管控逻辑与普通隐私权限不同,simctl的隐私命令暂未覆盖该权限。

替代解决方案

1. 授予权限

手动操作

  • 首次启动应用时,直接点击权限弹窗的「Allow」按钮;
  • 进入模拟器的「设置」->「隐私与安全性」->「跟踪」,找到目标应用并开启权限开关。

代码模拟权限状态

通过Method Swizzling替换ATTrackingManager的权限请求方法,直接返回已授权状态,适合单元测试或快速验证场景:

import AppTrackingTransparency
import ObjectiveC

extension ATTrackingManager {
    static func swizzleTrackingAuth() {
        let originalSel = #selector(requestTrackingAuthorization(completionHandler:))
        let swizzledSel = #selector(swizzled_requestTrackingAuth(completionHandler:))
        
        guard let originalMethod = class_getInstanceMethod(self, originalSel),
              let swizzledMethod = class_getInstanceMethod(self, swizzledSel) else { return }
        
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
    
    @objc private func swizzled_requestTrackingAuth(completionHandler: @escaping (ATTrackingManager.AuthorizationStatus) -> Void) {
        // 模拟已授权,可替换为.notDetermined/.denied/.restricted实现不同场景
        completionHandler(.authorized)
    }
}

// 在App启动时调用(如AppDelegate或SceneDelegate的启动方法)
ATTrackingManager.swizzleTrackingAuth()

XCUITest自动化操作

编写UI测试用例,自动处理权限弹窗或修改设置页面的权限:

import XCTest

class TrackingPermissionUITests: XCTestCase {
    let app = XCUIApplication()
    
    override func setUp() {
        super.setUp()
        continueAfterFailure = false
    }
    
    // 处理启动时的权限弹窗
    func testGrantPermissionViaAlert() {
        app.launch()
        let allowBtn = app.buttons["Allow"]
        if allowBtn.waitForExistence(timeout: 5) {
            allowBtn.tap()
        }
    }
    
    // 通过设置页面授予权限
    func testGrantPermissionInSettings() {
        app.terminate()
        let settingsApp = XCUIApplication(bundleIdentifier: "com.apple.Preferences")
        settingsApp.launch()
        
        settingsApp.tables.cells["Privacy & Security"].tap()
        settingsApp.tables.cells["Tracking"].tap()
        
        let appSwitch = settingsApp.switches["YourAppDisplayName"]
        if appSwitch.waitForExistence(timeout: 5), appSwitch.value as? String == "0" {
            appSwitch.tap()
        }
        
        settingsApp.terminate()
        app.launch()
    }
}

2. 检查权限状态

  • 代码层面:直接调用ATTrackingManager.trackingAuthorizationStatus获取当前权限状态,返回值包括.authorized、.denied、.notDetermined、.restricted;
  • XCUITest层面:可通过检查设置页面中应用的权限开关状态,或在应用内验证权限相关功能的行为来判断权限是否已授予。

3. 撤销权限

手动操作

  • 进入模拟器「设置」->「隐私与安全性」->「跟踪」,关闭目标应用的权限开关;
  • 重置模拟器内容和设置(会清除所有数据,适合彻底重置场景)。

XCUITest自动化操作

类似授予权限的逻辑,编写用例关闭设置页面的权限开关:

func testRevokePermissionInSettings() {
    app.terminate()
    let settingsApp = XCUIApplication(bundleIdentifier: "com.apple.Preferences")
    settingsApp.launch()
    
    settingsApp.tables.cells["Privacy & Security"].tap()
    settingsApp.tables.cells["Tracking"].tap()
    
    let appSwitch = settingsApp.switches["YourAppDisplayName"]
    if appSwitch.waitForExistence(timeout: 5), appSwitch.value as? String == "1" {
        appSwitch.tap()
    }
    
    settingsApp.terminate()
}

重置应用容器(清除数据)

通过simctl命令删除应用容器,会清除应用的所有数据及权限设置:

xcrun simctl erase_app $DEVICE_ID $BUNDLE_ID

内容的提问来源于stack exchange,提问作者Amos Joshua

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 15:25:20