Làm cách nào để xác định xem ứng dụng của tôi có chạy trong trình giả lập iphone không?


270

Như câu hỏi, tôi chủ yếu muốn biết liệu mã của tôi có chạy trong trình giả lập hay không, nhưng cũng sẽ quan tâm đến việc biết phiên bản iphone cụ thể đang chạy hoặc được mô phỏng.

EDIT: Tôi đã thêm từ 'lập trình' vào tên câu hỏi. Vấn đề của tôi là có thể tự động bao gồm / loại trừ mã tùy thuộc vào phiên bản / trình giả lập nào đang chạy, vì vậy tôi thực sự đang tìm kiếm thứ gì đó như chỉ thị tiền xử lý có thể cung cấp cho tôi thông tin này.


Tôi không chắc chắn một chỉ thị tiền xử lý là động (mặc dù đó có thể là những gì bạn đang tìm kiếm). Lệnh này có nghĩa là bạn thực sự biết, khi bạn xây dựng nó, nơi nó sẽ chạy lên.
WiseOldDuck

Câu trả lời:


356

Đã hỏi, nhưng với một tiêu đề rất khác nhau.

Những gì #defines được Xcode thiết lập khi biên dịch cho iPhone

Tôi sẽ lặp lại câu trả lời của tôi từ đó:

Nó nằm trong tài liệu SDK trong phần "Biên dịch mã nguồn theo điều kiện"

Định nghĩa có liên quan là TARGET_OS_SIMULATOR, được định nghĩa trong /usr/include/TargetCond điều kiện.h trong khung iOS. Trên các phiên bản trước của toolchain, bạn phải viết:

#include "TargetConditionals.h"

nhưng điều này không còn cần thiết trên chuỗi công cụ hiện tại (Xcode 6 / iOS8).

Vì vậy, ví dụ, nếu bạn muốn kiểm tra xem bạn có đang chạy trên thiết bị không, bạn nên làm

#if TARGET_OS_SIMULATOR
    // Simulator-specific code
#else
    // Device-specific code
#endif

tùy thuộc vào đó là phù hợp cho trường hợp sử dụng của bạn.


1
Cảm ơn. Tôi đồng ý với bạn đây là phiên bản cụ thể hơn cho câu hỏi ban đầu của bạn. Nếu bạn đã tìm thấy trong tìm kiếm ban đầu của tôi, tôi thậm chí sẽ không cần phải hỏi.
Jeffrey Meyer

5
Hãy cẩn thận với những định nghĩa này. Khi bạn biên dịch mã với mục menu 'Project> Set SDK hoạt động> Trình mô phỏng mô phỏng', vì TARGET_IPHONE_SIMULATOR là các biến TARGET_OS_IPHONE đều được xác định! Vì vậy, cách duy nhất đúng để phân tách logic được chỉ ra dưới đây bởi Pete (Cảm ơn anh chàng).
Vadim

5
Xem sự khác biệt #if và #ifdef. Đối với tôi đó là nguyên nhân của hành vi không chính xác.
Anton

7
Có lẽ nhu cầu bao gồm TargetCond điều kiện đã bị giảm kể từ khi điều này được viết, nhưng chỉ muốn lưu ý rằng #if TARGET_IPHONE_SIMULATOR hoạt động mà không bao gồm TargetCond điều kiện.h ngay bây giờ.
ngày

1
@Dimitris Đó là thực hành tốt. Bạn không biết TARGET_OS_SIMULATOR đã được xác định như thế nào, vì vậy! (TARGET_OS_SIMULATOR) có thể không giống với! TARGET_OS_SIMULATOR
Airsource Ltd

106

Mã cập nhật:

Đây là mục đích để làm việc chính thức.

#if TARGET_IPHONE_SIMULATOR
NSString *hello = @"Hello, iPhone simulator!";
#elif TARGET_OS_IPHONE
NSString *hello = @"Hello, device!";
#else
NSString *hello = @"Hello, unknown target!";
#endif

Bài gốc (kể từ khi không dùng nữa)

Mã này sẽ cho bạn biết nếu bạn đang chạy trong một trình giả lập.

#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif

7
Kể từ iOS 8 và Xcode 6.1.1, TARGET_OS_IPHONE là đúng trên trình giả lập.
malhal

3
điều này không còn quan tâm nữa trên các phiên bản XCode mới hơn
Fabio Napodano

1
Trừ khi bạn vào năm 2016 và chạy trình giả lập 64 bit. Hoặc vào năm 2019 và chạy mã của bạn trên iPhone với bộ xử lý Intel.
gnasher729

61

Không phải chỉ thị tiền xử lý, nhưng đây là những gì tôi đang tìm kiếm khi đến câu hỏi này;

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}

9
[model compare:iPhoneSimulator] == NSOrderedSamenên được viết là[model isEqualToString:iPhoneSimulator]
user102008

18
Hoặc [model hasSuffix:@"Simulator"]nếu bạn chỉ quan tâm đến "trình giả lập" nói chung, không phải iPhone hay iPad nói riêng. Câu trả lời này sẽ không hoạt động cho trình giả lập iPad :)
Nuthatch

Được ủng hộ vì nhận xét của Nuthatch khiến đây là câu trả lời hay nhất trong toto.
Le Mot Juated

12
Trong iOS9, hãy kiểm tra thiết bị namethay vìmodel
n.Drake

1
Mã sẽ không hoạt động nếu người dùng thêm Simulatortừ vào tên thiết bị của mình
mbelsky

55

Cách tốt nhất để làm điều này là:

#if TARGET_IPHONE_SIMULATOR

và không

#ifdef TARGET_IPHONE_SIMULATOR

vì nó luôn được xác định: 0 hoặc 1


39

ĐÂY LÀ MỘT CÁCH TỐT HƠN NGAY BÂY GIỜ!

Kể từ Xcode 9.3 beta 4, bạn có thể sử dụng #if targetEnvironment(simulator)để kiểm tra.

#if targetEnvironment(simulator)
//Your simulator code
#endif

CẬP NHẬT
SDK Xcode 10 và iOS 12 cũng hỗ trợ điều này.


1
Đây là cách duy nhất hiệu quả với tôi, phần còn lại của các giải pháp không hoạt động.
Vrutin Rathod

Lưu ý Điều này chỉ trong nhanh chóng.
Matt S.

35

Trong trường hợp của Swift, chúng tôi có thể thực hiện như sau

Chúng tôi có thể tạo cấu trúc cho phép bạn tạo dữ liệu có cấu trúc

struct Platform {
    static var isSimulator: Bool {
        #if targetEnvironment(simulator)
            // We're on the simulator
            return true
        #else
            // We're on a device
             return false
        #endif
    }
}

Sau đó, nếu chúng tôi muốn Phát hiện nếu ứng dụng đang được xây dựng cho thiết bị hoặc trình giả lập trong Swift thì.

if Platform.isSimulator {
    // Do one thing
} else {
    // Do the other
}

Theo tôi, việc thực hiện sạch nhất và nó chiếm các kiến ​​trúc x86_64 và i386. Đã giúp tôi khắc phục một thiết bị kỳ lạ so với lỗi giả lập trong Dữ liệu cốt lõi. Bạn là đàn ông!
Iron John Bonney

5
Trong Sân chơi, bạn sẽ nhận được cảnh báo, "Mã sau khi 'trở về' sẽ không bao giờ được thực thi". Vì vậy tôi nghĩ #if #else #endifsẽ tốt hơn.
DawnSong

12

Hoạt động cho Swift 5Xcode 11.3.1

Sử dụng mã này:

#if targetEnvironment(simulator)
   // Simulator
#else
   // Device
#endif

9

Tất cả những câu trả lời là tốt, nhưng bằng cách nào đó nó gây nhầm lẫn cho người mới như tôi vì nó không làm rõ kiểm tra biên dịch và kiểm tra thời gian chạy. Bộ tiền xử lý trước thời gian biên dịch, nhưng chúng ta nên làm cho nó rõ ràng hơn

Bài viết trên blog này cho thấy Làm thế nào để phát hiện trình giả lập iPhone? thông suốt

Thời gian chạy

Trước hết, hãy thảo luận ngắn gọn. UIDevice cung cấp cho bạn thông tin về thiết bị

[[UIDevice currentDevice] model]

sẽ trả lại cho bạn iPhone iPhone Simulator hay hoặc iPhone iPhone theo nơi ứng dụng đang chạy.

Thời gian biên dịch

Tuy nhiên, những gì bạn muốn là sử dụng thời gian biên dịch xác định. Tại sao? Bởi vì bạn biên dịch ứng dụng của mình một cách nghiêm ngặt để được chạy trong Trình mô phỏng hoặc trên thiết bị. Apple đưa ra một định nghĩa được gọi là TARGET_IPHONE_SIMULATOR. Vì vậy, hãy nhìn vào mã:

#if TARGET_IPHONE_SIMULATOR

NSLog(@"Running in Simulator - no app store or giro");

#endif

1
Làm thế nào để cải thiện các câu trả lời khác?
dùng151019

@Mark Nó làm rõ một chút
onmyway133

5
Hiện nay, trong Xcode 7, iOS 9 Simulator [[UIDevice currentDevice] model]đang trở lại iPhonecũng thay iPhone Simulator. Vì vậy, tôi nghĩ rằng đây không phải là cách tiếp cận tốt nhất.
eMdOS

6

Các câu trả lời trước là một chút ngày. Tôi thấy rằng tất cả những gì bạn cần làm là truy vấn TARGET_IPHONE_SIMULATORmacro ( không cần bao gồm bất kỳ tệp tiêu đề nào khác [giả sử bạn đang mã hóa cho iOS]).

Tôi đã thử TARGET_OS_IPHONEnhưng nó trả về cùng một giá trị (1) khi chạy trên thiết bị và trình giả lập thực tế, đó là lý do tôi khuyên bạn nên sử dụng TARGET_IPHONE_SIMULATORthay thế.


TARGET_OS_IPHONE dành cho mã có thể chạy trên iOS hoặc trên MacOS X. Rõ ràng bạn sẽ muốn mã đó hoạt động theo cách "iPhone" trên trình giả lập.
gnasher729

6

Để phân biệt giữa các ứng dụng mac: #if (arch (i386) || arch (x86_64)) &&! Os (OSX) // chúng tôi đang sử dụng trình giả lập chạy trên mac chứ không phải ứng dụng mac. (Đối với mã nền tảng chéo được bao gồm trong các mục tiêu mac)
Bobjt

4

Tôi đã có cùng một vấn đề, cả hai TARGET_IPHONE_SIMULATORTARGET_OS_IPHONEluôn luôn được xác định, và được đặt thành 1. Tất nhiên, giải pháp của Pete hoạt động, nhưng nếu bạn từng tình cờ xây dựng một thứ gì đó không phải là intel (không chắc, nhưng ai biết được), thì đây là thứ an toàn như miễn là phần cứng của iphone không thay đổi (vì vậy mã của bạn sẽ luôn hoạt động cho các điện thoại thông minh hiện có ngoài đó):

#if defined __arm__ || defined __thumb__
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_OS_IPHONE
#else
#define TARGET_IPHONE_SIMULATOR 1
#undef TARGET_OS_IPHONE
#endif

Đặt nó ở đâu đó thuận tiện, và sau đó giả vờ rằng các TARGET_*hằng số được xác định chính xác.


4

Có ai đã xem xét câu trả lời được cung cấp ở đây ?

Tôi cho rằng tương đương mục tiêu-c sẽ là

+ (BOOL)isSimulator {
    NSOperatingSystemVersion ios9 = {9, 0, 0};
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
    if ([processInfo isOperatingSystemAtLeastVersion:ios9]) {
        NSDictionary<NSString *, NSString *> *environment = [processInfo environment];
        NSString *simulator = [environment objectForKey:@"SIMULATOR_DEVICE_NAME"];
        return simulator != nil;
    } else {
        UIDevice *currentDevice = [UIDevice currentDevice];
        return ([currentDevice.model rangeOfString:@"Simulator"].location != NSNotFound);
    }
}

4

Dành cho Swift 4.2 / xCode 10

Tôi đã tạo một tiện ích mở rộng trên UIDevice, vì vậy tôi có thể dễ dàng hỏi xem trình giả lập có đang chạy hay không.

// UIDevice+CheckSimulator.swift

import UIKit

extension UIDevice {

    /// Checks if the current device that runs the app is xCode's simulator
    static func isSimulator() -> Bool {        
        #if targetEnvironment(simulator)
            return true
        #else
            return false
        #endif
    }
}

Trong tôi appdelegate ví dụ tôi sử dụng phương pháp này để quyết định thời tiết đăng ký thông báo từ xa là cần thiết, mà không phải là có thể cho mô phỏng.

// CHECK FOR REAL DEVICE / OR SIMULATOR
if UIDevice.isSimulator() == false {

    // REGISTER FOR SILENT REMOTE NOTIFICATION
    application.registerForRemoteNotifications()
}

1

Để bao gồm tất cả các loại "mô phỏng"

NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
    // we are running in a simulator
}

4
Nó không liên quan gì đến Xcode 7. Nếu bạn chạy iOS Simulator với iOS8 (từ Xcode 7) thì điều này sẽ hoạt động. Nó sẽ không hoạt động cho iOS9 khi mô hình [[UIDevice currentDevice]] chỉ trả về "iPhone" nếu ứng dụng được khởi chạy từ Trình mô phỏng iOS
tesla

tại sao không -[NSString containsString]?
Gobe

1

Với Swift 4.2 (Xcode 10), chúng ta có thể làm điều này

#if targetEnvironment(simulator)
  //simulator code
#else 
  #warning("Not compiling for simulator")
#endif

1
Chỉ cần một bản sao khác dán
J. Doe

0

Câu trả lời của tôi dựa trên câu trả lời và nhận xét của @Daniel Magnusson của @Nuthatch và @ n.Drake. và tôi viết nó để tiết kiệm thời gian cho người dùng nhanh chóng làm việc trên iOS9 trở đi.

Đây là những gì làm việc cho tôi:

if UIDevice.currentDevice().name.hasSuffix("Simulator"){
    //Code executing on Simulator
} else{
    //Code executing on Device
}

1
Mã sẽ không hoạt động nếu người dùng thêm Simulatortừ vào tên thiết bị của mình
mbelsky

Thật không may với XCode 8 UIDevice.current.namebáo cáo tên của máy mà Trình mô phỏng đang chạy (thường là một cái gì đó giống như "Simon's MacBook Pro" bây giờ) nên thử nghiệm đã trở nên không đáng tin cậy. Tôi vẫn đang tìm cách khắc phục nó.
Michael

0

/// Trả về true nếu giả lập và không phải là thiết bị

public static var isSimulator: Bool {
    #if (arch(i386) || arch(x86_64)) && os(iOS)
        return true
    #else
        return false
    #endif
}

0

Apple đã thêm hỗ trợ để kiểm tra ứng dụng được nhắm mục tiêu cho trình giả lập với các mục sau:

#if targetEnvironment(simulator)
let DEVICE_IS_SIMULATOR = true
#else
let DEVICE_IS_SIMULATOR = false
#endif

0

nếu không có gì làm việc, hãy thử cái này

public struct Platform {

    public static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0 // Use this line in Xcode 7 or newer
    }

}

-4

Theo tôi, câu trả lời (được trình bày ở trên và lặp lại bên dưới):

NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
    //device is simulator
}

là câu trả lời tốt nhất bởi vì nó rõ ràng được thực hiện tại RUNTIME so với việc là TRỰC TIẾP MÁY TÍNH.


11
Tôi không đồng ý. Mã này kết thúc trong sản phẩm của bạn, trong khi chỉ thị của trình biên dịch giữ cho - trên thiết bị không cần thiết - không cần thiết.
chín viên đá

1
Các chỉ thị của trình biên dịch hoạt động vì thiết bị và trình giả lập là các mục tiêu biên dịch hoàn toàn khác nhau - tức là bạn sẽ không sử dụng cùng một nhị phân trên cả hai. Nó được biên dịch để phần cứng khác nhau, vì vậy nó có ý nghĩa trong trường hợp đó.
Brad

Bị xử tử tại RUNTIME khiến nó trở thành câu trả lời tồi tệ nhất có thể.
gnasher729

-4

Điều này làm việc cho tôi tốt nhất

NSString *name = [[UIDevice currentDevice] name];


if ([name isEqualToString:@"iPhone Simulator"]) {

}

2
Trên Xcode 7.3, iPhone 6 Plus Simulator trở lại "iPhone".
Eric
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.