كيف يمكنني تحديد ما إذا كان تطبيقي يعمل برمجيًا في جهاز محاكاة iPhone؟
-
19-08-2019 - |
سؤال
كما يشير السؤال، أود بشكل أساسي معرفة ما إذا كان الكود الخاص بي يعمل في جهاز المحاكاة أم لا، ولكني مهتم أيضًا بمعرفة إصدار iPhone المحدد الذي يتم تشغيله أو تتم محاكاته.
يحرر:أضفت كلمة "برمجيًا" إلى اسم السؤال.الهدف من سؤالي هو أن أكون قادرًا على تضمين/استبعاد التعليمات البرمجية ديناميكيًا اعتمادًا على الإصدار/المحاكي الذي يتم تشغيله، لذلك سأبحث حقًا عن شيء مثل توجيه ما قبل المعالج الذي يمكن أن يزودني بهذه المعلومات.
المحلول
وسأل إذا، ولكن مع عنوان مختلف للغاية.
ما #defines تم إعدادها من قبل كسكودي عندما تجميع آيفون
وسوف أكرر جوابي من هناك:
وانها في مستندات SDK تحت عنوان "تجميع شفرة المصدر مشروط"
والتعريف ذات الصلة هو TARGET_OS_SIMULATOR، التي تم تعريفها في /usr/include/TargetConditionals.h في إطار دائرة الرقابة الداخلية. في الإصدارات السابقة من toolchain، كان عليك أن تكتب:
#include "TargetConditionals.h"
ولكن هذا لم يعد من الضروري على (إكس كود 6 / iOS8) toolchain الحالي.
وهكذا، على سبيل المثال، إذا كنت تريد أن تتأكد من يعمل على الجهاز، يجب عليك القيام به
#if TARGET_OS_SIMULATOR
// Simulator-specific code
#else
// Device-specific code
#endif
واعتمادا على يناسب استخدامك حدة.
نصائح أخرى
تحليل كود تحديث:
وهذا هو المفترض للعمل رسميا.
#if TARGET_IPHONE_SIMULATOR
NSString *hello = @"Hello, iPhone simulator!";
#elif TARGET_OS_IPHONE
NSString *hello = @"Hello, device!";
#else
NSString *hello = @"Hello, unknown target!";
#endif
تحليل الأصل وظيفة <م> (منذ موقوف) م>
تحليلوهذا الرمز سوف اقول لك إذا كنت تعمل في جهاز محاكاة.
#ifdef __i386__
NSLog(@"Running in the simulator");
#else
NSLog(@"Running on a device");
#endif
وليس قبل معالج التوجيه، ولكن هذا ما كنت أبحث عنه عندما جئت إلى هذه المسألة؛
NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
//device is simulator
}
وأفضل طريقة للقيام بذلك هي:
#if TARGET_IPHONE_SIMULATOR
وليس
#ifdef TARGET_IPHONE_SIMULATOR
ومنذ المحددة لها دائما: 0 أو 1
هناك طريقة أفضل الآن!
اعتبارًا من الإصدار التجريبي الرابع من Xcode 9.3، يمكنك استخدامه #if targetEnvironment(simulator)
للتأكد.
#if targetEnvironment(simulator)
//Your simulator code
#endif
تحديث
يدعم Xcode 10 وiOS 12 SDK هذا أيضًا.
في حالة Swift يمكننا تنفيذ ما يلي
يمكننا إنشاء هيكل يسمح لك بإنشاء بيانات منظمة
struct Platform {
static let isSimulator: Bool = {
#if arch(i386) || arch(x86_64)
return true
#endif
return false
}()
}
ثم إذا أردنا اكتشاف ما إذا كان التطبيق مصممًا لجهاز أو جهاز محاكاة في Swift، فعندئذٍ.
if Platform.isSimulator {
// Do one thing
}
else {
// Do the other
}
كل هذه الإجابات جيدة، لكنها تربك بطريقة أو بأخرى المبتدئين مثلي لأنها لا توضح التحقق من الترجمة والتحقق من وقت التشغيل.المعالج المسبق موجود قبل وقت الترجمة، ولكن يجب أن نجعل الأمر أكثر وضوحًا
تظهر هذه المقالة بلوق كيفية الكشف عن محاكي iPhone؟ بوضوح
مدة العرض
أولا وقبل كل شيء، دعونا نناقش قريبا.يوفر لك UIDevice بالفعل معلومات حول الجهاز
[[UIDevice currentDevice] model]
سيعيد لك "iPhone Simulator" أو "iPhone" وفقًا لمكان تشغيل التطبيق.
وقت الترجمة
لكن ما تريده هو استخدام وقت الترجمة المحدد.لماذا؟لأنك تقوم بتجميع تطبيقك بشكل صارم ليتم تشغيله إما داخل جهاز المحاكاة أو على الجهاز.تقدم شركة Apple تعريفًا يسمى TARGET_IPHONE_SIMULATOR
.لذلك دعونا نلقي نظرة على الكود:
#if TARGET_IPHONE_SIMULATOR
NSLog(@"Running in Simulator - no app store or giro");
#endif
ويعمل لSwift 4
وXcode 9.4.1
استخدم هذا الرمز:
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
الإجابات السابقة مؤرخة قليلاً.لقد وجدت أن كل ما عليك فعله هو الاستعلام عن TARGET_IPHONE_SIMULATOR
دقيق (لا حاجة لتضمين أي ملفات رأس أخرى [بافتراض أنك تقوم بالبرمجة لنظام iOS]).
حاولت TARGET_OS_IPHONE
ولكنها أعادت نفس القيمة (1) عند التشغيل على جهاز ومحاكي فعليين، ولهذا السبب أوصي باستخدامه TARGET_IPHONE_SIMULATOR
بدلاً من.
في سويفت:
#if (arch(i386) || arch(x86_64))
...
#endif
وكان لي نفس المشكلة، يتم تعريف كل من TARGET_IPHONE_SIMULATOR
وTARGET_OS_IPHONE
دائما، ويتم تعيين إلى 1. يعمل حل بيت، بطبيعة الحال، ولكن إذا كنت يحدث من أي وقت مضى أن نبني على شيء آخر غير إنتل (غير محتمل، ولكن من يدري)، وهنا شيء أن يكون في مأمن طالما لا يتغير الأجهزة فون (حتى التعليمات البرمجية ستعمل دائما من أجل فون حاليا هناك):
#if defined __arm__ || defined __thumb__
#undef TARGET_IPHONE_SIMULATOR
#define TARGET_OS_IPHONE
#else
#define TARGET_IPHONE_SIMULATOR 1
#undef TARGET_OS_IPHONE
#endif
والتي وضعت في مكان مناسب، ثم نتظاهر بأن الثوابت TARGET_*
تم تعريفها بشكل صحيح.
لسويفت 4.2 / xCode 10
لقد قمت بإنشاء ملحق على UDevice، لذا يمكنني بسهولة السؤال عما إذا كان جهاز المحاكاة قيد التشغيل.
// 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
}
}
في AppDelegate على سبيل المثال، أستخدم هذه الطريقة لتحديد ما إذا كان التسجيل للإشعارات عن بعد ضروريًا، وهو أمر غير ممكن لجهاز المحاكاة.
// CHECK FOR REAL DEVICE / OR SIMULATOR
if UIDevice.isSimulator() == false {
// REGISTER FOR SILENT REMOTE NOTIFICATION
application.registerForRemoteNotifications()
}
هل قام أي شخص يعتبر الجواب قدمت <لأ href = "https://github.com/EddyVerbruggen/nativescript-secure-storage/blob/70aa5e88691c073312e334c9963c444c3f4d86d5/secure-storage.ios.ts#L12-L24" يختلط = "نوفولو noreferrer "> هنا ؟
وأعتقد أن ما يعادل الهدف-ج أن يكون
+ (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);
}
}
لتشمل جميع أنواع "محاكاة"
NSString *model = [[UIDevice currentDevice] model];
if([model rangeOfString:@"Simulator" options:NSCaseInsensitiveSearch].location !=NSNotFound)
{
// we are running in a simulator
}
ومع سويفت 4.2 (كسكودي 10)، يمكننا أن نفعل هذا
#if targetEnvironment(simulator)
//simulator code
#else
#warning("Not compiling for simulator")
#endif
ويستند جوابي علىDaniel ماجنوسون الجواب وتعليقاتNuthatch و @n.Drake. وأنا أكتب لإنقاذ بعض الوقت للمستخدمين بسرعة العمل على iOS9 وما بعده.
وهذا ما عملت بالنسبة لي:
if UIDevice.currentDevice().name.hasSuffix("Simulator"){
//Code executing on Simulator
} else{
//Code executing on Device
}
و/// عرض true إذا كانت محاكاة وليس جهاز
public static var isSimulator: Bool {
#if (arch(i386) || arch(x86_64)) && os(iOS)
return true
#else
return false
#endif
}
وأبل قد أضاف للتحقق من التطبيق لجهاز محاكاة بما يلي:
#if targetEnvironment(simulator)
let DEVICE_IS_SIMULATOR = true
#else
let DEVICE_IS_SIMULATOR = false
#endif
إذا لم ينجح شيء، جرب هذا
public struct Platform {
public static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0 // Use this line in Xcode 7 or newer
}
}
وهذا عمل بالنسبة لي أفضل
NSString *name = [[UIDevice currentDevice] name];
if ([name isEqualToString:@"iPhone Simulator"]) {
}
في رأيي، فإن الجواب (عرض أعلاه وتتكرر أدناه):
NSString *model = [[UIDevice currentDevice] model];
if ([model isEqualToString:@"iPhone Simulator"]) {
//device is simulator
}
وهو أفضل إجابة لأنه يتم تنفيذ الواضح في RUNTIME مقابل كونه DIRECTIVE ترجمة.