Swift アプリが Xcode から実行されているかどうかを検出する 質問する

Swift アプリが Xcode から実行されているかどうかを検出する 質問する

iOSアプリがXCodeから直接実行されているかどうかをプログラムで判断したい(シミュレータまたはテザリングされたデバイスのいずれか)。説明されている-D DEBUGソリューションを試しました。ここしかし、Xcodeから切断してアプリを再実行すると、まだデバッグモードであると認識されます。私が探しているのは、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 );
}

ベストアンサー1

説明:Cコード(および以下のSwiftバージョン)は、プログラムが以下の環境で実行されているかどうかを確認します。デバッガ制御、Xcode から実行されている場合はそうではありません。Xcode の外部でプログラムをデバッグすることはできます (lldb または gdb を直接呼び出すことによって)。また、デバッグせずに Xcode からプログラムを実行することもできます (スキーム設定の「実行可能ファイルのデバッグ」チェックボックスがオフになっている場合)。


C関数をそのままSwiftから呼び出すこともできます。Swift から Objective-C コードを呼び出すにはどうすればいいですか?純粋な 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必要ありません。
  • CintタイプはInt32スイフトです。
  • sizeof(info)strideOfValue(info)構造体のパディングを含めるには、C コードの部分を 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
}

おすすめ記事