【问题标题】:Detect if Swift app is being run from Xcode检测 Swift 应用程序是否正在从 Xcode 运行
【发布时间】:2016-01-15 14:27:16
【问题描述】:

我想以编程方式确定 iOS 应用程序是否直接从 XCode 运行(在模拟器中或在连接的设备上)。 我已经尝试了here 描述的 -D DEBUG 解决方案,但是当我断开与 Xcode 的连接并重新运行应用程序时,它仍然认为它处于调试模式。 我想我正在寻找的是this function的Swift版本@

#include <assert.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>

static bool AmIBeingDebugged(void)
    // Returns true if the current process is being debugged (either 
    // running under the debugger or has a debugger attached post facto).
{
    int                 junk;
    int                 mib[4];
    struct kinfo_proc   info;
    size_t              size;

    // Initialize the flags so that, if sysctl fails for some bizarre 
    // reason, we get a predictable result.

    info.kp_proc.p_flag = 0;

    // Initialize mib, which tells sysctl the info we want, in this case
    // we're looking for information about a specific process ID.

    mib[0] = CTL_KERN;
    mib[1] = KERN_PROC;
    mib[2] = KERN_PROC_PID;
    mib[3] = getpid();

    // Call sysctl.
    size = sizeof(info);
    junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
    assert(junk == 0);

    // We're being debugged if the P_TRACED flag is set.
    return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}

【问题讨论】:

  • 你可以从 Swift 中调用 C 函数,所以你不需要翻译它。
  • 马丁,这就是我要提出的答案,把它作为答案,我会投票赞成。
  • 这是一个快速的、未经测试的将代码转换为 Swift 的尝试(只是为了好玩):gist.github.com/getaaron/8d48489274a873835636。我现在没有时间进一步玩它,但也许它会让你开始。
  • @Knight0fDragon:将其翻译成 Swift 是更有趣的挑战 :)

标签: ios xcode swift


【解决方案1】:

澄清:您的 C 代码(以及下面的 Swift 版本)检查是否 程序在调试器控制下运行, 如果它正在运行,则不是 Xcode。可以在 Xcode 之外调试程序(通过调用 lldb 或 gdb 直接),并且可以从 Xcode 运行程序而无需调试它 (如果方案设置中的“调试可执行文件”复选框处于关闭状态)。


您可以简单地保留 C 函数并从 Swift 调用它。 How do I call Objective-C code from Swift? 中给出的方法也适用于纯 C 代码。

但实际上将该代码翻译成 Swift 并不太复杂:

func amIBeingDebugged() -> Bool {
    // Buffer for "sysctl(...)" call's result.
    var info = kinfo_proc()
    // Counts buffer's size in bytes (like C/C++'s `sizeof`).
    var size = MemoryLayout.stride(ofValue: info)
    // Tells we want info about own process.
    var mib : [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
    // Call the API (and assert success).
    let junk = sysctl(&mib, UInt32(mib.count), &info, &size, nil, 0)
    assert(junk == 0, "sysctl failed")
    // Finally, checks if debugger's flag is present yet.
    return (info.kp_proc.p_flag & P_TRACED) != 0
}

Swift 5 (Xcode 10.7) 更新strideofValue 和相关功能不存在了, 它们已被 MemoryLayout.stride(ofValue:) 取代。

备注:

  • kinfo_proc() 创建一个完全初始化的结构,其中包含所有 字段设置为零,因此不需要设置info.kp_proc.p_flag = 0
  • C int 类型是 Int32 是 Swift。
  • C 代码中的sizeof(info) 必须是strideOfValue(info) 在 Swift 中包含结构填充。与sizeofValue(info) 上面的代码在 64 位设备的模拟器中总是返回 false。这是最难弄清楚的部分。

Swift 2 逻辑:

func amIBeingDebugged() -> Bool {
    var info = kinfo_proc()
    var mib : [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
    var size = strideofValue(info)
    let junk = sysctl(&mib, UInt32(mib.count), &info, &size, nil, 0)
    assert(junk == 0, "sysctl failed")
    return (info.kp_proc.p_flag & P_TRACED) != 0
}

【讨论】:

  • 很高兴找到strideOfValue。我不知道有什么区别。
  • 嗨 Martin,你能提供一个 Obj-C 版本的 Xcode 8 解决方案来检测调试器吗? Apple提供的一个似乎不再正常工作。谢谢! :-)
  • @HansKnoechel:问题中的代码是纯 C 代码,可以毫无问题地从 Objective-C 中使用。它怎么不能“正常工作”?
【解决方案2】:

对于那些寻求更简单解决方案的人 - 这非常有效:

func isDebuggerAttached() -> Bool {
    return getppid() != 1
}

【讨论】:

    猜你喜欢
    • 2015-01-30
    • 2019-11-22
    • 2015-06-27
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2017-06-05
    相关资源
    最近更新 更多