Detecting if iPhone or iPad without opting for Universal App - ios

I really want this to work:
if UIDevice.current.userInterfaceIdiom == .pad {
print("iPad")
} else {
print("not iPad")
}
However, my app only prints "not iPad" even though I am using an iPad. I have Devices (under Deployment Info) set to iPhone. If I change this to Universal it works, but I don't want a universal app, I just want to be able to detect if an iPhone or iPad is being used (even though the app is for iPhones, due to compatibility mode it still can be run on iPads).
So how can I detect if the device is an iPad or iPhone without changing my app to Universal? Thanks

You can check the model:
if UIDevice.current.model.hasPrefix("iPad") {
print("it is an iPad")
} else {
print("it is not an iPad")
}

One thing you can do is get the inner-screen width of the page. Phones are generally below 786 px and you can call everything else an iPad. Use can do something like this
var width = window.innerWidth;
If (width > 786px) {
print(‘ipad’);
} else {
print(‘not ipad’)
}

iPhone Only app can be downloaded to iPad. But in current scenario, we doesn't have device that's much smaller resolution(deployment target: 9).
OBJ-C
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && [[[UIDevice currentDevice] model] hasPrefix:#"iPad"]) {
// This app is an iPhone app running on an iPad
NSLog(#"This app is an iPhone app running on an iPad");
}
Swift
if UIDevice.current.userInterfaceIdiom == .phone, UIDevice.current.model.hasPrefix("iPad") {
print("iPad")
}

Try this,
print("Model - \(UIDevice.current.model)")

Related

How to detect current device using SwiftUI?

I am trying to determine whether the device being used is iPhone or iPad.
Please see this question: Detect current device with UI_USER_INTERFACE_IDIOM() in Swift
That solution works if you use UIKit. But
What is the equivalent method if you are using SwiftUI ?
You can find the device type, like this:
if UIDevice.current.userInterfaceIdiom == .pad {
...
}
You can use this:
UIDevice.current.localizedModel
In your case, an implementation method could be:
if UIDevice.current.localizedModel == "iPhone" {
print("This is an iPhone")
} else if UIDevice.current.localizedModel == "iPad" {
print("This is an iPad")
}
Obviously, you can use this for string interpolation such as this (assuming the current device type is an iPhone):
HStack {
Text("Device Type: ")
Text(UIDevice.current.localizedModel)
}
//Output:
//"Device Type: iPhone"
It will return the device type. (iPhone, iPad, AppleWatch) No further imports are necessary aside from SwiftUI which should have already been imported upon creation of your project if you selected SwiftUI as the interface.
NOTE: It does not return the device model (despite the ".localizedModel")
Hope this helps!
UIDevice is no longer available from WatchKit 2 on
WKInterfaceDevice could be helpful: https://developer.apple.com/documentation/watchkit/wkinterfacedevice
i.e.:
let systemName = WKInterfaceDevice.current().systemName
let systemVersion = WKInterfaceDevice.current().systemVersion
let deviceModel = WKInterfaceDevice.current().model

CMMotionActivityManager is unable to detect Automotive mode

I am using Core Motion Framework for detecting the device activity.
i.e. Walking, Running, Automotive, Stationary
The main issue is i am able to detect walking and running with great accuracy but my device is not able to detect the Automotive mode.
Here is my code
var motionActivityManager: CMMotionActivityManager?
if CMMotionActivityManager.isActivityAvailable() {
motionActivityManager?.startActivityUpdatesToQueue(NSOperationQueue.currentQueue()!, withHandler: {
activityData
in
if activityData!.walking == true {
self.lblActivityStatus?.text = "Walking"
} else if activityData!.running == true {
self.lblActivityStatus?.text = "Running"
} else if activityData!.automotive == true {
self.lblActivityStatus?.text = "Automotive"
} else if activityData!.stationary == true {
self.lblActivityStatus?.text = "Stationary"
}
print("Activity Data: ", activityData)
})
}
I finally got the answer by testing the same app on multiple devices.
the m7 chip on first generation device is not working properly for particularly "Automotive" mode.
When i was testing on 5s and ipad air, it was not detecting Automotive mode as it should detect. But testing the same app with iphone 6 Plus, it worked fine.
so the problem was with device not with framework.

How to tell which device I'm on in Xcode UI Testing?

While an Xcode UI Test is running, I want to know which device/environment is being used (e.g. iPad Air 2, iOS 9.0, Simulator).
How can I get this information?
Using Swift 3 (change .pad to .phone as necessary):
if UIDevice.current.userInterfaceIdiom == .pad {
// Ipad specific checks
}
Using older versions of Swift:
UIDevice.currentDevice().userInterfaceIdiom
Unfortunately there is no direct way of querying the current device. However you can work around by querying the size classes of the device:
private func isIpad(app: XCUIApplication) -> Bool {
return app.windows.elementBoundByIndex(0).horizontalSizeClass == .Regular && app.windows.elementBoundByIndex(0).verticalSizeClass == .Regular
}
As you can see in the Apple Description of size classes, only iPad devices (currently) have both vertical and horizontal size class "Regular".
You can check using the windows element frame XCUIApplication().windows.element(boundBy: 0).frame and check the device type.
You can also set an extension for XCUIDevice with a currentDevice property:
/// Device types
public enum Devices: CGFloat {
/// iPhone
case iPhone4 = 480
case iPhone5 = 568
case iPhone7 = 667
case iPhone7Plus = 736
/// iPad - Portraite
case iPad = 1024
case iPadPro = 1366
/// iPad - Landscape
case iPad_Landscape = 768
case iPadPro_Landscape = 0
}
/// Check current device
extension XCUIDevice {
public static var currentDevice:Devices {
get {
let orientation = XCUIDevice.shared().orientation
let frame = XCUIApplication().windows.element(boundBy: 0).frame
switch orientation {
case .landscapeLeft, .landscapeRight:
return frame.width == 1024 ? .iPadPro_Landscape : Devices(rawValue: frame.width)!
default:
return Devices(rawValue: frame.height)!
}
}
}
}
Usage
let currentDevice = XCUIDevice.currentDevice
Maybe someone would be come in handy the same for XCTest on Objective C:
// Check if the device is iPhone
if ( ([[app windows] elementBoundByIndex:0].horizontalSizeClass != XCUIUserInterfaceSizeClassRegular) || ([[app windows] elementBoundByIndex:0].verticalSizeClass != XCUIUserInterfaceSizeClassRegular) ) {
// do something for iPhone
}
else {
// do something for iPad
}
Swift: 5.2.4
Xcode: 11.6
var isiPad: Bool {
return UIDevice.current.userInterfaceIdiom == .pad
}
With iOS13+, you can now use UITraitCollection.current to get the complete set of traits for the current environment. (This is the "iOS interface environment for your app, including traits such as horizontal and vertical size class, display scale, and user interface idiom." doc)
In your case, you can access its property .userInterfaceIdiom to check for one of the device types in the UIUserInterfaceIdiom enumeration.
As an aside, if you just want to get the horizontal/vertical size classes of the trait collection, you can be more backwards compatible with your tests (Xcode 10.0+) just by accessing myXCUIElement.horizontalSizeClass and .verticalSizeClass within your test, as they are exposed via the XCUIElementAttributes protocol that all UI elements adopt. (Note though that I was getting .unspecified when calling off of XCUIApplication(); best to use a real UI element in a window. If you don't have one on hand, you can always still use something like app!.windows.element(boundBy: 0).horizontalSizeClass == .regular as mentioned in the past.)

UI_USER_INTERFACE_IDIOM() crashes app distributed on devices ONLY

I created a sample single page swift language based iOS app that CRASHES on this func call in viewDidLoad() -
func regularFont() -> UIFont {
var fontSize : CGFloat = (UI_USER_INTERFACE_IDIOM() == .Pad) ? 15 : 12
return UIFont.systemFontOfSize(fontSize)
}
But once I replace this UI_USER_INTERFACE_IDIOM() with Apple recommended UIDevice() method, it WORKS fine.
func regularFont() -> UIFont {
var fontSize : CGFloat = (UIDevice().userInterfaceIdiom == .Pad) ? 15 : 12
return UIFont.systemFontOfSize(fontSize)
}
The crash occurs on all devices I tested - iPhone 5s, iPhone 6 and iPad Air (all on iOS 8.x) and it happens ONLY on devices, NOT simulator.
PS: The app is installed on all devices through our OTA/web link.
To my surprise, we have another objective c language based app on Apple's App Store that uses UI_USER_INTERFACE_IDIOM() heavily, regularly updated... but never crashed due to this.
Any thoughts?
UI_USER_INTERFACE_IDIOM() is just an Objective-C macro, which is defined as:
#define UI_USER_INTERFACE_IDIOM() \ ([[UIDevice currentDevice] respondsToSelector:#selector(userInterfaceIdiom)] ? \ [[UIDevice currentDevice] userInterfaceIdiom] : \ UIUserInterfaceIdiomPhone)
So when you work with Swift, you need to use as:
UIDevice.currentDevice().userInterfaceIdiom == .Pad
UIDevice.currentDevice().userInterfaceIdiom == .Phone
UIDevice.currentDevice().userInterfaceIdiom == .Unspecified
Hope this could help.
I got it (partially!). Actually "release" implementation of UI_USER_INTERFACE_IDIOM() in swift project crashes the app.
Once I edit the scheme to "release" (Xcode > Product > Scheme > Edit Scheme > Run > Build Configuration change to "Release") and then run on simulator/device, the app crashes everywhere.. all devices/simulators/developer/distribution profiles.
However, still I have no clue why our app store app (objective c language based) does NOT crash.
My only guess is that it's a glitch in UI_USER_INTERFACE_IDIOM() API implementation with some language specific coding (swift vs objective c) by Apple.
Anyways, I would replace all UI_USER_INTERFACE_IDIOM() with UIDevice(). userInterfaceIdiom. I hope this helps someone!
Swift 5.3 and up:
if UIDevice.current.userInterfaceIdiom != .pad {
// do stuff
}

How do I create an if statement like the one below for iPad screen size?

I am trying to create a universal app, and I am just wondering how I write the following code to direct it to iPad version of app. Specifically what should the navtiveBounds.height be for the iPad Air and Mini.
Thanks So Much :)
if UIScreen.mainScreen().nativeBounds.height == 2208 {
println("iPhone 6+")
let delay = SKAction.waitForDuration(1)
let transition = SKAction.runBlock({
let scene = Menu6Plus(size: self.size)
self.view?.presentScene(scene)
})
runAction(SKAction.sequence([delay, transition]))
}
You can use:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// Code for iPad!
}
Also, I believe that if you were to use the nativeBounds property to determine screen size, iPad and iPad mini would both return the same 1024-by-768 resolution.
If you really need to detect if the user is running an iPad Mini at runtime, try this:
Is it possible to detect that your iOS app is running on an iPad mini at runtime?

Resources