diff --git a/.github/workflows/device_info_plus.yaml b/.github/workflows/device_info_plus.yaml index 7403b99129..d44783a388 100644 --- a/.github/workflows/device_info_plus.yaml +++ b/.github/workflows/device_info_plus.yaml @@ -88,7 +88,7 @@ jobs: script: ./.github/workflows/scripts/integration-test.sh android device_info_plus_example ios_example_build: - runs-on: macos-14 + runs-on: macos-15 timeout-minutes: 30 steps: - name: "Checkout repository" @@ -101,7 +101,7 @@ jobs: run: ./.github/workflows/scripts/build-examples.sh ios ./lib/main.dart ios_integration_test: - runs-on: macos-14 + runs-on: macos-15 timeout-minutes: 30 steps: - name: "Checkout repository" @@ -115,12 +115,12 @@ jobs: - name: "Start Simulator" uses: futureware-tech/simulator-action@v4 with: - model: 'iPhone 15' + model: 'iPhone 16' - name: "Run Integration Test" run: ./.github/workflows/scripts/integration-test.sh ios device_info_plus_example macos_example_build: - runs-on: macos-14 + runs-on: macos-15 timeout-minutes: 30 steps: - name: "Checkout repository" @@ -133,7 +133,7 @@ jobs: run: ./.github/workflows/scripts/build-examples.sh macos ./lib/main.dart macos_integration_test: - runs-on: macos-14 + runs-on: macos-15 timeout-minutes: 30 steps: - name: "Checkout repository" diff --git a/packages/device_info_plus/device_info_plus/example/integration_test/device_info_plus_test.dart b/packages/device_info_plus/device_info_plus/example/integration_test/device_info_plus_test.dart index 84d2630492..bf8cd3c970 100644 --- a/packages/device_info_plus/device_info_plus/example/integration_test/device_info_plus_test.dart +++ b/packages/device_info_plus/device_info_plus/example/integration_test/device_info_plus_test.dart @@ -117,6 +117,7 @@ void main() { expect(macosInfo.hostName, isNotNull); expect(macosInfo.arch, isNotNull); expect(macosInfo.model, isNotNull); + expect(macosInfo.modelName, isNotNull); expect(macosInfo.kernelVersion, isNotNull); expect(macosInfo.osRelease, isNotNull); expect(macosInfo.activeCPUs, isNotNull); diff --git a/packages/device_info_plus/device_info_plus/example/ios/Flutter/AppFrameworkInfo.plist b/packages/device_info_plus/device_info_plus/example/ios/Flutter/AppFrameworkInfo.plist index 4f8d4d2456..8c6e56146e 100644 --- a/packages/device_info_plus/device_info_plus/example/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/device_info_plus/device_info_plus/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/packages/device_info_plus/device_info_plus/example/ios/Runner.xcodeproj/project.pbxproj b/packages/device_info_plus/device_info_plus/example/ios/Runner.xcodeproj/project.pbxproj index 90d1082afa..075d8eecde 100644 --- a/packages/device_info_plus/device_info_plus/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/device_info_plus/device_info_plus/example/ios/Runner.xcodeproj/project.pbxproj @@ -214,7 +214,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C8080294A63A400263BE5 = { @@ -451,7 +451,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -579,7 +579,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -628,7 +628,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/packages/device_info_plus/device_info_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/device_info_plus/device_info_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 87131a09be..8e3ca5dfe1 100644 --- a/packages/device_info_plus/device_info_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/device_info_plus/device_info_plus/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -24,6 +26,8 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -43,9 +47,5 @@ UIViewControllerBasedStatusBarAppearance - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/packages/device_info_plus/device_info_plus/example/lib/main.dart b/packages/device_info_plus/device_info_plus/example/lib/main.dart index 5ea541c5dd..c188b03538 100644 --- a/packages/device_info_plus/device_info_plus/example/lib/main.dart +++ b/packages/device_info_plus/device_info_plus/example/lib/main.dart @@ -112,6 +112,7 @@ class _MyAppState extends State { 'systemName': data.systemName, 'systemVersion': data.systemVersion, 'model': data.model, + 'modelName': data.modelName, 'localizedModel': data.localizedModel, 'identifierForVendor': data.identifierForVendor, 'isPhysicalDevice': data.isPhysicalDevice, @@ -166,6 +167,7 @@ class _MyAppState extends State { 'hostName': data.hostName, 'arch': data.arch, 'model': data.model, + 'modelName': data.modelName, 'kernelVersion': data.kernelVersion, 'majorVersion': data.majorVersion, 'minorVersion': data.minorVersion, diff --git a/packages/device_info_plus/device_info_plus/example/macos/Runner.xcodeproj/project.pbxproj b/packages/device_info_plus/device_info_plus/example/macos/Runner.xcodeproj/project.pbxproj index 02a8e04d7d..17738f85dc 100644 --- a/packages/device_info_plus/device_info_plus/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/device_info_plus/device_info_plus/example/macos/Runner.xcodeproj/project.pbxproj @@ -259,7 +259,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { diff --git a/packages/device_info_plus/device_info_plus/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/device_info_plus/device_info_plus/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index bcdcdc013c..7bb1c7dfdf 100644 --- a/packages/device_info_plus/device_info_plus/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/device_info_plus/device_info_plus/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Bool { return true diff --git a/packages/device_info_plus/device_info_plus/example/pubspec.yaml b/packages/device_info_plus/device_info_plus/example/pubspec.yaml index d54544c328..718ea2f843 100644 --- a/packages/device_info_plus/device_info_plus/example/pubspec.yaml +++ b/packages/device_info_plus/device_info_plus/example/pubspec.yaml @@ -1,5 +1,6 @@ name: device_info_plus_example description: Demonstrates how to use the device_info_plus plugin. +version: 1.0.0 dependencies: flutter: diff --git a/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.m b/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.m new file mode 100644 index 0000000000..cda41d953f --- /dev/null +++ b/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.m @@ -0,0 +1,208 @@ +// +// DeviceIdentifiers.m +// device_info_plus +// +// Created by Volodymyr on 06.11.2024. +// +#import "./include/device_info_plus/DeviceIdentifiers.h" + +@implementation DeviceIdentifiers + ++ (NSString *)userKnownDeviceModel:(NSString *)identifier { + if ([identifier isEqualToString:@"iPhone6,1"]) { + return @"iPhone 5s"; + } else if ([identifier isEqualToString:@"iPhone6,2"]) { + return @"iPhone 5s"; + } else if ([identifier isEqualToString:@"iPhone7,2"]) { + return @"iPhone 6"; + } else if ([identifier isEqualToString:@"iPhone7,1"]) { + return @"iPhone 6 Plus"; + } else if ([identifier isEqualToString:@"iPhone8,1"]) { + return @"iPhone 6s"; + } else if ([identifier isEqualToString:@"iPhone8,2"]) { + return @"iPhone 6s Plus"; + } else if ([identifier isEqualToString:@"iPhone9,1"] || + [identifier isEqualToString:@"iPhone9,3"]) { + return @"iPhone 7"; + } else if ([identifier isEqualToString:@"iPhone9,2"] || + [identifier isEqualToString:@"iPhone9,4"]) { + return @"iPhone 7 Plus"; + } else if ([identifier isEqualToString:@"iPhone8,4"]) { + return @"iPhone SE"; + } else if ([identifier isEqualToString:@"iPhone10,1"] || + [identifier isEqualToString:@"iPhone10,4"]) { + return @"iPhone 8"; + } else if ([identifier isEqualToString:@"iPhone10,2"] || + [identifier isEqualToString:@"iPhone10,5"]) { + return @"iPhone 8 Plus"; + } else if ([identifier isEqualToString:@"iPhone10,3"] || + [identifier isEqualToString:@"iPhone10,6"]) { + return @"iPhone X"; + } else if ([identifier isEqualToString:@"iPhone11,2"]) { + return @"iPhone XS"; + } else if ([identifier isEqualToString:@"iPhone11,4"] || + [identifier isEqualToString:@"iPhone11,6"]) { + return @"iPhone XS Max"; + } else if ([identifier isEqualToString:@"iPhone11,8"]) { + return @"iPhone XR"; + } else if ([identifier isEqualToString:@"iPhone12,1"]) { + return @"iPhone 11"; + } else if ([identifier isEqualToString:@"iPhone12,3"]) { + return @"iPhone 11 Pro"; + } else if ([identifier isEqualToString:@"iPhone12,5"]) { + return @"iPhone 11 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone12,8"]) { + return @"iPhone SE 2"; + } else if ([identifier isEqualToString:@"iPhone13,2"]) { + return @"iPhone 12"; + } else if ([identifier isEqualToString:@"iPhone13,1"]) { + return @"iPhone 12 Mini"; + } else if ([identifier isEqualToString:@"iPhone13,3"]) { + return @"iPhone 12 Pro"; + } else if ([identifier isEqualToString:@"iPhone13,4"]) { + return @"iPhone 12 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone14,5"]) { + return @"iPhone 13"; + } else if ([identifier isEqualToString:@"iPhone14,4"]) { + return @"iPhone 13 Mini"; + } else if ([identifier isEqualToString:@"iPhone14,2"]) { + return @"iPhone 13 Pro"; + } else if ([identifier isEqualToString:@"iPhone14,3"]) { + return @"iPhone 13 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone14,6"]) { + return @"iPhone SE 3"; + } else if ([identifier isEqualToString:@"iPhone14,7"]) { + return @"iPhone 14"; + } else if ([identifier isEqualToString:@"iPhone14,8"]) { + return @"iPhone 14 Plus"; + } else if ([identifier isEqualToString:@"iPhone15,2"]) { + return @"iPhone 14 Pro"; + } else if ([identifier isEqualToString:@"iPhone15,3"]) { + return @"iPhone 14 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone15,4"]) { + return @"iPhone 15"; + } else if ([identifier isEqualToString:@"iPhone15,5"]) { + return @"iPhone 15 Plus"; + } else if ([identifier isEqualToString:@"iPhone16,1"]) { + return @"iPhone 15 Pro"; + } else if ([identifier isEqualToString:@"iPhone16,2"]) { + return @"iPhone 15 Pro Max"; + } else if ([identifier isEqualToString:@"iPhone17,3"]) { + return @"iPhone 16"; + } else if ([identifier isEqualToString:@"iPhone17,4"]) { + return @"iPhone 16 Plus"; + } else if ([identifier isEqualToString:@"iPhone17,1"]) { + return @"iPhone 16 Pro"; + } else if ([identifier isEqualToString:@"iPhone17,2"]) { + return @"iPhone 16 Pro Max"; + // iPads + } else if ([identifier isEqualToString:@"iPad4,1"] || + [identifier isEqualToString:@"iPad4,2"] || + [identifier isEqualToString:@"iPad4,3"]) { + return @"iPad Air"; + } else if ([identifier isEqualToString:@"iPad5,3"] || + [identifier isEqualToString:@"iPad5,4"]) { + return @"iPad Air 2"; + } else if ([identifier isEqualToString:@"iPad6,11"] || + [identifier isEqualToString:@"iPad6,12"]) { + return @"iPad 5"; + } else if ([identifier isEqualToString:@"iPad7,5"] || + [identifier isEqualToString:@"iPad7,6"]) { + return @"iPad 6"; + } else if ([identifier isEqualToString:@"iPad11,3"] || + [identifier isEqualToString:@"iPad11,4"]) { + return @"iPad Air 3"; + } else if ([identifier isEqualToString:@"iPad7,11"] || + [identifier isEqualToString:@"iPad7,12"]) { + return @"iPad 7"; + } else if ([identifier isEqualToString:@"iPad11,6"] || + [identifier isEqualToString:@"iPad11,7"]) { + return @"iPad 8"; + } else if ([identifier isEqualToString:@"iPad12,1"] || + [identifier isEqualToString:@"iPad12,2"]) { + return @"iPad 9"; + } else if ([identifier isEqualToString:@"iPad13,18"] || + [identifier isEqualToString:@"iPad13,19"]) { + return @"iPad 10"; + } else if ([identifier isEqualToString:@"iPad13,1"] || + [identifier isEqualToString:@"iPad13,2"]) { + return @"iPad Air 4"; + } else if ([identifier isEqualToString:@"iPad13,16"] || + [identifier isEqualToString:@"iPad13,17"]) { + return @"iPad Air 5"; + } else if ([identifier isEqualToString:@"iPad14,8"] || + [identifier isEqualToString:@"iPad14,9"]) { + return @"iPad Air 11-Inch M2"; + } else if ([identifier isEqualToString:@"iPad14,10"] || + [identifier isEqualToString:@"iPad14,11"]) { + return @"iPad Air 13-Inch M2"; + } else if ([identifier isEqualToString:@"iPad2,5"] || + [identifier isEqualToString:@"iPad2,6"] || + [identifier isEqualToString:@"iPad2,7"]) { + return @"iPad Mini"; + } else if ([identifier isEqualToString:@"iPad4,4"] || + [identifier isEqualToString:@"iPad4,5"] || + [identifier isEqualToString:@"iPad4,6"]) { + return @"iPad Mini 2"; + } else if ([identifier isEqualToString:@"iPad4,7"] || + [identifier isEqualToString:@"iPad4,8"] || + [identifier isEqualToString:@"iPad4,9"]) { + return @"iPad Mini 3"; + } else if ([identifier isEqualToString:@"iPad5,1"] || + [identifier isEqualToString:@"iPad5,2"]) { + return @"iPad Mini 4"; + } else if ([identifier isEqualToString:@"iPad11,1"] || + [identifier isEqualToString:@"iPad11,2"]) { + return @"iPad Mini 5"; + } else if ([identifier isEqualToString:@"iPad14,1"] || + [identifier isEqualToString:@"iPad14,2"]) { + return @"iPad Mini 6"; + } else if ([identifier isEqualToString:@"iPad6,3"] || + [identifier isEqualToString:@"iPad6,4"]) { + return @"iPad Pro 9-Inch"; + } else if ([identifier isEqualToString:@"iPad6,7"] || + [identifier isEqualToString:@"iPad6,8"]) { + return @"iPad Pro 12-Inch"; + } else if ([identifier isEqualToString:@"iPad7,1"] || [identifier isEqualToString:@"iPad7,2"]) { + return @"iPad Pro 12-Inch 2"; + } else if ([identifier isEqualToString:@"iPad7,3"] || [identifier isEqualToString:@"iPad7,4"]) { + return @"iPad Pro 10-Inch"; + } else if ([identifier isEqualToString:@"iPad8,1"] || [identifier isEqualToString:@"iPad8,2"] || + [identifier isEqualToString:@"iPad8,3"] || [identifier isEqualToString:@"iPad8,4"]) { + return @"iPad Pro 11-Inch"; + } else if ([identifier isEqualToString:@"iPad8,5"] || [identifier isEqualToString:@"iPad8,6"] || + [identifier isEqualToString:@"iPad8,7"] || [identifier isEqualToString:@"iPad8,8"]) { + return @"iPad Pro 12-Inch 3"; + } else if ([identifier isEqualToString:@"iPad8,9"] || + [identifier isEqualToString:@"iPad8,10"]) { + return @"iPad Pro 11-Inch 2"; + } else if ([identifier isEqualToString:@"iPad8,11"] || + [identifier isEqualToString:@"iPad8,12"]) { + return @"iPad Pro 12-Inch 4"; + } else if ([identifier isEqualToString:@"iPad13,4"] || + [identifier isEqualToString:@"iPad13,5"] || + [identifier isEqualToString:@"iPad13,6"] || + [identifier isEqualToString:@"iPad13,7"]) { + return @"iPad Pro 11-Inch 3"; + } else if ([identifier isEqualToString:@"iPad13,8"] || + [identifier isEqualToString:@"iPad13,9"] || + [identifier isEqualToString:@"iPad13,10"] || + [identifier isEqualToString:@"iPad13,11"]) { + return @"iPad Pro 12-Inch 5"; + } else if ([identifier isEqualToString:@"iPad14,3"] || + [identifier isEqualToString:@"iPad14,4"]) { + return @"iPad Pro 11-Inch 4"; + } else if ([identifier isEqualToString:@"iPad14,5"] || + [identifier isEqualToString:@"iPad14,6"]) { + return @"iPad Pro 12-Inch 6"; + } else if ([identifier isEqualToString:@"iPad16,3"] || + [identifier isEqualToString:@"iPad16,4"]) { + return @"iPad Pro 11-Inch (M4)"; + } else if ([identifier isEqualToString:@"iPad16,5"] || + [identifier isEqualToString:@"iPad16,6"]) { + return @"iPad Pro 13-Inch (M4)"; + } else { + return @"Unknown device"; + } +} +@end diff --git a/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/FPPDeviceInfoPlusPlugin.m b/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/FPPDeviceInfoPlusPlugin.m index 199fd93523..2b495c7c17 100644 --- a/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/FPPDeviceInfoPlusPlugin.m +++ b/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/FPPDeviceInfoPlusPlugin.m @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "./include/device_info_plus/FPPDeviceInfoPlusPlugin.h" +#import "./include/device_info_plus/DeviceIdentifiers.h" #import @implementation FPPDeviceInfoPlusPlugin @@ -29,17 +30,21 @@ - (void)handleMethodCall:(FlutterMethodCall *)call isiOSAppOnMac = [NSNumber numberWithBool:[info isiOSAppOnMac]]; } NSString *machine; + NSString *deviceName; if ([self isDevicePhysical]) { machine = @(un.machine); } else { machine = [info environment][@"SIMULATOR_MODEL_IDENTIFIER"]; } + deviceName = [DeviceIdentifiers userKnownDeviceModel:machine]; + result(@{ @"name" : [device name], @"systemName" : [device systemName], @"systemVersion" : [device systemVersion], @"model" : [device model], @"localizedModel" : [device localizedModel], + @"modelName" : deviceName, @"identifierForVendor" : [[device identifierForVendor] UUIDString] ?: [NSNull null], @"isPhysicalDevice" : isPhysicalNumber, diff --git a/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/DeviceIdentifiers.h b/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/DeviceIdentifiers.h new file mode 100644 index 0000000000..0f5c8d70ff --- /dev/null +++ b/packages/device_info_plus/device_info_plus/ios/device_info_plus/Sources/device_info_plus/include/device_info_plus/DeviceIdentifiers.h @@ -0,0 +1,13 @@ +// +// DeviceIdentifiers.h +// device_info_plus +// +// Created by Volodymyr on 06.11.2024. +// +#import + +@interface DeviceIdentifiers : NSObject + ++ (NSString *)userKnownDeviceModel:(NSString *)identifier; + +@end diff --git a/packages/device_info_plus/device_info_plus/lib/src/model/ios_device_info.dart b/packages/device_info_plus/device_info_plus/lib/src/model/ios_device_info.dart index 78ac9aa36a..aaf654a776 100644 --- a/packages/device_info_plus/device_info_plus/lib/src/model/ios_device_info.dart +++ b/packages/device_info_plus/device_info_plus/lib/src/model/ios_device_info.dart @@ -15,6 +15,7 @@ class IosDeviceInfo extends BaseDeviceInfo { required this.systemName, required this.systemVersion, required this.model, + required this.modelName, required this.localizedModel, this.identifierForVendor, required this.isPhysicalDevice, @@ -38,10 +39,14 @@ class IosDeviceInfo extends BaseDeviceInfo { /// https://developer.apple.com/documentation/uikit/uidevice/1620043-systemversion final String systemVersion; - /// Device model. + /// Device model according to OS /// https://developer.apple.com/documentation/uikit/uidevice/1620044-model final String model; + /// Commercial or user-known model name + /// Examples: `iPhone 16 Pro`, `iPad Pro 11-Inch 3` + final String modelName; + /// Localized name of the device model. /// https://developer.apple.com/documentation/uikit/uidevice/1620029-localizedmodel final String localizedModel; @@ -68,6 +73,7 @@ class IosDeviceInfo extends BaseDeviceInfo { systemName: map['systemName'], systemVersion: map['systemVersion'], model: map['model'], + modelName: map['modelName'], localizedModel: map['localizedModel'], identifierForVendor: map['identifierForVendor'], isPhysicalDevice: map['isPhysicalDevice'], diff --git a/packages/device_info_plus/device_info_plus/lib/src/model/macos_device_info.dart b/packages/device_info_plus/device_info_plus/lib/src/model/macos_device_info.dart index 76c5c01f55..7725c5d1de 100644 --- a/packages/device_info_plus/device_info_plus/lib/src/model/macos_device_info.dart +++ b/packages/device_info_plus/device_info_plus/lib/src/model/macos_device_info.dart @@ -13,6 +13,7 @@ class MacOsDeviceInfo extends BaseDeviceInfo { required this.hostName, required this.arch, required this.model, + required this.modelName, required this.kernelVersion, required this.osRelease, required this.majorVersion, @@ -34,9 +35,14 @@ class MacOsDeviceInfo extends BaseDeviceInfo { /// Note, that on Apple Silicon Macs can return `x86_64` if app runs via Rosetta final String arch; - /// Device model + /// Device model identifier + /// Examples: `MacBookPro18,3`, `Mac16,2`. final String model; + /// Device model name + /// Examples: `MacBook Pro (16-inch, 2021)`, `iMac (24-inch, 2024)`. + final String modelName; + /// Machine Kernel version. /// Examples: /// `Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64` @@ -76,6 +82,7 @@ class MacOsDeviceInfo extends BaseDeviceInfo { hostName: map['hostName'], arch: map['arch'], model: map['model'], + modelName: map['modelName'], kernelVersion: map['kernelVersion'], osRelease: map['osRelease'], majorVersion: map['majorVersion'], diff --git a/packages/device_info_plus/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.swift b/packages/device_info_plus/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.swift new file mode 100644 index 0000000000..288808c159 --- /dev/null +++ b/packages/device_info_plus/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceIdentifiers.swift @@ -0,0 +1,99 @@ +import Foundation + +// Models list is taken from support.apple.com +// Example of the list with models https://support.apple.com/en-us/102869 + +func getMacModelName(modelNumber: String) -> String { + switch modelNumber { + // MacBook models (2015 and later) + case "MacBook8,1": return "MacBook (12-inch, 2015)" + case "MacBook9,1": return "MacBook (12-inch, 2016)" + case "MacBook10,1": return "MacBook (12-inch, 2017)" + + // MacBook Air models (2013 and later) + case "MacBookAir6,1": return "MacBook Air (11-inch, 2013)" + case "MacBookAir6,2": return "MacBook Air (13-inch, 2013)" + case "MacBookAir7,1": return "MacBook Air (11-inch, 2015)" + case "MacBookAir7,2": return "MacBook Air (13-inch, 2015-2017)" + case "MacBookAir8,1": return "MacBook Air (13-inch, 2018)" + case "MacBookAir8,2": return "MacBook Air (13-inch, 2019)" + case "MacBookAir9,1": return "MacBook Air (13-inch, 2020)" + case "MacBookAir10,1": return "MacBook Air (13-inch, 2020)" + case "Mac14,2": return "MacBook Air (13-inch, 2022)" + case "Mac14,15": return "MacBook Air (15-inch, 2023)" + case "Mac15,12": return "MacBook Air (13-inch, 2024)" + case "Mac15,13": return "MacBook Air (15-inch, 2024)" + + // MacBook Pro models (2012 and later) + case "MacBookPro10,1": return "MacBook Pro (15-inch, 2012-2013)" + case "MacBookPro10,2": return "MacBook Pro (13-inch, 2012-2013)" + case "MacBookPro11,1": return "MacBook Pro (13-inch, 2013-2014)" + case "MacBookPro11,2", "MacBookPro11,3": return "MacBook Pro (15-inch, 2013-2014)" + case "MacBookPro11,4", "MacBookPro11,5": return "MacBook Pro (15-inch, 2015)" + case "MacBookPro12,1": return "MacBook Pro (13-inch, 2015)" + case "MacBookPro13,1": return "MacBook Pro (13-inch, 2016)" + case "MacBookPro13,2": return "MacBook Pro (13-inch, 2016)" + case "MacBookPro13,3": return "MacBook Pro (15-inch, 2016)" + case "MacBookPro14,1": return "MacBook Pro (13-inch, 2017)" + case "MacBookPro14,2": return "MacBook Pro (13-inch, 2017)" + case "MacBookPro14,3": return "MacBook Pro (15-inch, 2017)" + case "MacBookPro15,1", "MacBookPro15,3": return "MacBook Pro (15-inch, 2018-2019)" + case "MacBookPro15,2": return "MacBook Pro (13-inch, 2018-2019)" + case "MacBookPro15,4": return "MacBook Pro (13-inch, 2019)" + case "MacBookPro16,1", "MacBookPro16,4": return "MacBook Pro (16-inch, 2019)" + case "MacBookPro16,2": return "MacBook Pro (13-inch, 2019)" + case "MacBookPro16,3": return "MacBook Pro (13-inch, 2020)" + case "MacBookPro17,1": return "MacBook Pro (13-inch, 2020)" + case "MacBookPro18,1": return "MacBook Pro (14-inch, 2021)" + case "MacBookPro18,2": return "MacBook Pro (16-inch, 2021)" + case "MacBookPro18,3": return "MacBook Pro (16-inch, 2021)" + case "Mac14,5", "Mac14,9": return "MacBook Pro (14-inch, 2023)" + case "Mac14,6", "Mac14,10": return "MacBook Pro (14-inch, 2023)" + case "Mac14,7": return "MacBook Pro (13-inch, 2022)" + case "Mac15,3": return "MacBook Pro (14-inch, 2023)" + case "Mac15,6", "Mac15,8", "Mac15.10": return "MacBook Pro (14-inch, 2023)" + case "Mac15,7", "Mac15,9", "Mac15.11": return "MacBook Pro (16-inch, 2023)" + + // iMac models (2013 and later) + case "iMac13,1": return "iMac (21.5-inch, 2013)" + case "iMac13,2": return "iMac (27-inch, 2013)" + case "iMac14,1": return "iMac (21.5-inch, 2014)" + case "iMac14,2": return "iMac (27-inch, 2014)" + case "iMac14,4": return "iMac (21.5-inch, 2014)" + case "iMac15,1": return "iMac (27-inch, 2014-2015)" + case "iMac16,1","iMac16,2": return "iMac (21.5-inch, 2015)" + case "iMac17,1": return "iMac (27-inch, 2015)" + case "iMac18,1": return "iMac (21.5-inch, 2017)" + case "iMac18,2": return "iMac (21.5-inch, 2017)" + case "iMac18,3": return "iMac (27-inch, 2017)" + case "iMac19,1": return "iMac (27-inch, 2019)" + case "iMac19,2": return "iMac (21.5-inch, 2019)" + case "iMac20,1", "iMac20,2": return "iMac (27-inch, 2020)" + case "iMac21,1", "iMac21,2": return "iMac (24-inch, 2021)" + case "Mac15,4", "Mac15,5": return "iMac (24-inch, 2023)" + case "Mac16,2", "Mac16,3": return "iMac (24-inch, 2024)" + + // Mac mini models (2012 and later) + case "MacMini6,1", "MacMini6,2": return "Mac mini (2012)" + case "MacMini7,1": return "Mac mini (2014)" + case "MacMini8,1": return "Mac mini (2018)" + case "MacMini9,1": return "Mac mini (2020)" + case "Mac14,12": return "Mac mini (2023)" + case "Mac14,3": return "Mac mini (2023)" + case "Mac16,15", "Mac16,10": return "Mac mini (2024)" + + // Mac Pro models (2013 and later) + case "MacPro6,1": return "Mac Pro (Late 2013)" + case "MacPro7,1": return "Mac Pro (2019)" + case "Mac14,8": return "Mac Pro (2023)" + + // iMac Pro + case "iMacPro1,1": return "iMac Pro (2017)" + + // Mac Studio (2022 and newer) + case "Mac13,1", "Mac13,2": return "Mac Studio (2022)" + case "Mac14,13", "Mac14,14": return "Mac Studio (2023)" + + default: return "Unknown Model" + } +} diff --git a/packages/device_info_plus/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceInfoPlusMacosPlugin.swift b/packages/device_info_plus/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceInfoPlusMacosPlugin.swift index 8dbeb74203..a1f6823606 100644 --- a/packages/device_info_plus/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceInfoPlusMacosPlugin.swift +++ b/packages/device_info_plus/device_info_plus/macos/device_info_plus/Sources/device_info_plus/DeviceInfoPlusMacosPlugin.swift @@ -22,6 +22,7 @@ public class DeviceInfoPlusMacosPlugin: NSObject, FlutterPlugin { let hostName = Sysctl.osType let arch = Sysctl.machine let model = Sysctl.model + let modelName = getMacModelName(modelNumber: Sysctl.model) let kernelVersion = Sysctl.version let osRelease = ProcessInfo.processInfo.operatingSystemVersionString let osVersion = ProcessInfo.processInfo.operatingSystemVersion; @@ -38,6 +39,7 @@ public class DeviceInfoPlusMacosPlugin: NSObject, FlutterPlugin { "hostName": hostName, "arch": arch, "model": model, + "modelName": modelName, "kernelVersion": kernelVersion, "osRelease": osRelease, "majorVersion": majorVersion, diff --git a/packages/device_info_plus/device_info_plus/test/model/ios_device_info_test.dart b/packages/device_info_plus/device_info_plus/test/model/ios_device_info_test.dart index 1a0a494c8e..158a17afda 100644 --- a/packages/device_info_plus/device_info_plus/test/model/ios_device_info_test.dart +++ b/packages/device_info_plus/device_info_plus/test/model/ios_device_info_test.dart @@ -17,6 +17,7 @@ void main() { iosDeviceInfoMap = { 'name': 'name', 'model': 'model', + 'modelName': 'modelName', 'utsname': iosUtsnameMap, 'systemName': 'systemName', 'isPhysicalDevice': true, @@ -32,6 +33,7 @@ void main() { test('fromMap should return $IosDeviceInfo with correct values', () { expect(iosDeviceInfo.name, 'name'); expect(iosDeviceInfo.model, 'model'); + expect(iosDeviceInfo.modelName, 'modelName'); expect(iosDeviceInfo.isPhysicalDevice, isTrue); expect(iosDeviceInfo.isiOSAppOnMac, isTrue); expect(iosDeviceInfo.systemName, 'systemName'); diff --git a/packages/device_info_plus/device_info_plus/test/model/macos_device_info_test.dart b/packages/device_info_plus/device_info_plus/test/model/macos_device_info_test.dart index 0f466608e5..ac196762e6 100644 --- a/packages/device_info_plus/device_info_plus/test/model/macos_device_info_test.dart +++ b/packages/device_info_plus/device_info_plus/test/model/macos_device_info_test.dart @@ -8,7 +8,8 @@ void main() { group('fromMap | data', () { const macosDeviceInfoMap = { 'arch': 'arch', - 'model': 'model', + 'model': 'Mac16,2', + 'modelName': 'iMac (24-inch, 2024)', 'activeCPUs': 4, 'memorySize': 16, 'cpuFrequency': 2, @@ -24,9 +25,9 @@ void main() { test('fromMap should return $MacOsDeviceInfo with correct values', () { final macosDeviceInfo = MacOsDeviceInfo.fromMap(macosDeviceInfoMap); - expect(macosDeviceInfo.arch, 'arch'); - expect(macosDeviceInfo.model, 'model'); + expect(macosDeviceInfo.model, 'Mac16,2'); + expect(macosDeviceInfo.modelName, 'iMac (24-inch, 2024)'); expect(macosDeviceInfo.activeCPUs, 4); expect(macosDeviceInfo.memorySize, 16); expect(macosDeviceInfo.cpuFrequency, 2);