← KlugDeviceType

Documentation

KlugDeviceType documentation

com.klug.devicetype

Complete developer guide: installation, phone or tablet layouts, own breakpoints, foldables and display size, API reference and troubleshooting.

iOSAndroid Version 1.0.0 Product page · Buy

Introduction

Many apps show a different layout on a tablet than on a phone. Guessing the device class from the stage size is unreliable: the result can change with orientation, display scaling and the size of the window. KlugDeviceType asks the operating system instead.

  • Android: the smallest screen width of the app's configuration in density-independent pixels (dp). 600 dp or more counts as a tablet, the same breakpoint Android uses for its own tablet layouts.
  • iOS: the system's interface idiom. An iPad is a tablet, an iPhone is a phone.

Besides the yes/no answer you get the smallest screen width itself (dp on Android, points on iOS) for your own breakpoints. No permission is needed.

Extension IDcom.klug.devicetype
Version1.0.0
PlatformsAndroid, iOS
ActionScript packagecom.klug.devicetype, one class: DeviceType
DeliveryThe extension file com.klug.devicetype.ane, the ActionScript library KlugDeviceType.swc and this documentation

Requirements

AIR SDK51.x (HARMAN)
iOSiOS 17 or later, iPhone and iPad
AndroidAndroid 6.0 (API 23) or later, phones, tablets and foldables
PermissionsNone
Other platformsmacOS, Windows and the AIR simulator: the extension can stay in the build; isSupported returns false, deviceType is an empty string and smallestWidthDp is -1.

Add the extension

Self-contained: no core library ANE and no dependency ANEs are needed. One file, one extensionID.

1 · Copy the files

Copy com.klug.devicetype.ane into your project's extension folder, for example extensions/. In your IDE add the .ane as a native extension of the project. When you build on the command line, compile against KlugDeviceType.swc as an external library and give adt the extension folder:

build.sh
amxmlc -external-library-path+=lib/KlugDeviceType.swc -output Main.swf src/Main.as

adt -package -target ipa-app-store ... -extdir extensions
adt -package -target aab ... -extdir extensions

2 · Declare it in the application descriptor

app.xml
<extensions>
    <extensionID>com.klug.devicetype</extensionID>
</extensions>

3 · Platform settings

KlugDeviceType needs no further entries in the application descriptor:

  • iOS: no InfoAdditions keys and no entitlements.
  • Android: no permissions, features, activities or services in <manifestAdditions>.
  • macOS and desktop: nothing to add.

Getting started

DeviceType is a singleton: always use DeviceType.getInstance(). The getters are synchronous; every read asks the operating system again, nothing is cached.

Main.as
import com.klug.devicetype.DeviceType;

var type:DeviceType = DeviceType.getInstance();

if ( !type.isSupported )   useDesktopLayout();   // your app: desktop, simulator
else if ( type.isTablet )  useTabletLayout();    // Android: 600 dp or more · iOS: iPad
else                       usePhoneLayout();

trace( type.deviceType, type.smallestWidthDp );   // for example "phone 411"

The answer is available from the first frame of the app, before you build the first layout.

Guides

Choose the layout at start

Use isTablet, isPhone or deviceType, whichever reads best in your code. They always agree: isPhone is the opposite of isTablet on Android and iOS, and all three are false or empty on other platforms.

Layout.as
import com.klug.devicetype.DeviceType;

var type:DeviceType = DeviceType.getInstance();

switch ( type.deviceType )
{
    case "tablet": buildTwoPaneLayout(); break;   // your app
    case "phone":  buildOnePaneLayout(); break;
    default:       buildDesktopLayout();          // "": not supported
}

Your own breakpoints with smallestWidthDp

smallestWidthDp returns the smaller of the two screen dimensions, so it does not depend on whether the device is held upright or sideways. On Android it is in dp, on iOS in points, which are comparable units. It is -1 where it is not available.

Grid.as
var sw:int = DeviceType.getInstance().smallestWidthDp;
var columns:int;

if ( sw >= 720 )        columns = 3;   // large tablet
else if ( sw >= 600 )   columns = 2;   // small tablet
else                    columns = 1;   // phone, or -1: not available

buildGrid( columns );                  // your app

On iOS isTablet follows the device idiom, not smallestWidthDp. If you want the same pixel rule on both platforms, compare smallestWidthDp yourself.

Orientation

Rotating the device does not change the answer: Android reports the smallest width independent of orientation, and on iOS the smaller screen dimension is used. You do not need to read the values again after a rotation; only your stage size changes.

Rotate.as
import flash.events.Event;

stage.addEventListener( Event.RESIZE, function( e:Event ):void {
    // device class unchanged: only lay out again for the new stage size
    layoutFor( stage.stageWidth, stage.stageHeight, type.isTablet );   // your app
});

Foldables, split screen and resizing

Some devices change their class while the app runs. A foldable phone opened to its large inner display can have a smallest width of 600 dp or more and become a "tablet"; folded again, it is a "phone". Because KlugDeviceType never caches, read it again whenever the stage is resized.

  • Android: the value comes from the app's current configuration. In split-screen or free-form windows Android can report the size of the app's window rather than the whole screen, so a tablet can report "phone" while the app occupies half of it.
  • iOS: isTablet follows the device and does not change. smallestWidthDp follows the screen the app is shown on; on a device with more than one display it changes when the app moves to the other display.
Resize.as
import com.klug.devicetype.DeviceType;
import flash.events.Event;

var type:DeviceType = DeviceType.getInstance();
var current:String = type.deviceType;

stage.addEventListener( Event.RESIZE, function( e:Event ):void {
    var now:String = type.deviceType;   // asks the system again
    if ( now == current ) return;       // a rotation alone never changes it
    current = now;
    rebuildLayout( now );               // your app
});

The Android "Display size" setting

Android lets users enlarge or shrink everything on screen under Settings → Display → Display size (the name varies by manufacturer). This setting changes the density and therefore the smallest width in dp. A small tablet with a larger display size can drop below 600 dp and report "phone", and a large phone with a smaller display size can reach 600 dp and report "tablet".

This is intended Android behaviour: the system's own apps switch their layouts at the same point. If your layout must follow the hardware rather than the user's setting, add your own margin around 600 dp, or let the user choose the layout in your settings.

DisplaySize.as
var sw:int = DeviceType.getInstance().smallestWidthDp;

// treat 560..639 dp as "uncertain": keep what the user chose last time
if ( sw >= 640 )      useTabletLayout();
else if ( sw >= 560 ) useSavedLayoutChoice();   // your app's setting
else                  usePhoneLayout();

iOS: iPhone apps on iPad, iPad apps on the Mac

isTablet reports the idiom the system gives the app. An iPhone-only app running on an iPad in compatibility mode is shown as a phone app and reports "phone". An iPad app running on a Mac with Apple silicon reports the iPad idiom. Use the stage size for the actual space you have.

Lifecycle and error handling

The getters can be called at any time, also in the background and right after returning. They never throw: on failure isTablet returns false (so isPhone returns true on Android and iOS) and smallestWidthDp returns -1. If your app keeps a cached copy, refresh it when the app returns, because the device may have been folded or the display size changed in the meantime.

Resume.as
import flash.desktop.NativeApplication;
import flash.events.Event;

NativeApplication.nativeApplication.addEventListener( Event.ACTIVATE, function( e:Event ):void {
    var now:String = DeviceType.getInstance().deviceType;
    if ( now != current ) { current = now; rebuildLayout( now ); }
});

API reference

Package com.klug.devicetype.

class DeviceType

MemberDescription
static getInstance():DeviceTypeReturns the single instance and creates it on the first call. Use this instead of the constructor. All platforms.
DeviceType()Constructor. Do not call it directly: a second instance throws an Error ("DeviceType is a singleton, use DeviceType.getInstance()").
isSupported:BooleanRead-only. True when the extension is available: Android and iOS. False on other platforms.
isTablet:BooleanRead-only. True on a tablet. Android: smallest screen width of 600 dp or more. iOS: iPad idiom. False on other platforms and when the value cannot be read.
isPhone:BooleanRead-only. The opposite of isTablet on Android and iOS. False on other platforms.
deviceType:StringRead-only. "tablet" or "phone" on Android and iOS; an empty string on other platforms.
smallestWidthDp:intRead-only. The smaller screen dimension. Android: smallest screen width of the app's configuration in dp. iOS: the smaller dimension of the screen the app is shown on, in points, rounded. -1 on other platforms and when not available.

Events

KlugDeviceType dispatches no events. All results are return values of the getters and are read fresh from the system on every call. To react to a fold, a window change or a display-size change, read the values again on the stage's Event.RESIZE or on Event.ACTIVATE (see Foldables, split screen and resizing).

Troubleshooting

A small Android tablet reports "phone".

Its smallest width is below 600 dp. This happens on small tablets, with a larger "Display size" setting, or while the app runs in split screen. Check smallestWidthDp and use your own breakpoint if needed (see Display size).

A large phone or foldable reports "tablet".

An opened foldable or a large phone with a smaller "Display size" setting can reach 600 dp. That is how Android classifies it as well; the app gets the same amount of space as on a small tablet.

The answer changed while the app was running.

On Android the device was folded or unfolded, the app's window changed, or the display size was changed. Read the values again on Event.RESIZE and rebuild the layout when deviceType changes.

smallestWidthDp is different from stage.stageWidth.

smallestWidthDp is in dp or points and refers to the screen. The stage size is in pixels and refers to your app's area. Use smallestWidthDp for the device class and the stage size for the layout itself.

isSupported is false and deviceType is empty.

You are running on desktop or in the AIR simulator, or the <extensionID> is missing from the application descriptor or the .ane was not packaged into the build.

Changelog

1.0.0 · update

  • iOS: smallestWidthDp follows the screen the app is shown on, so it changes when the app moves between displays on devices with more than one display.

1.0.0 · first release

  • Phone or tablet from the operating system: Android 600 dp rule, iOS device idiom.
  • isTablet, isPhone, deviceType and smallestWidthDp, read fresh on every call.
  • No permission needed; safe empty values on other platforms.