如何在Flutter中适配iOS16+ iPad获取用户自定义设备名
问题
我通过Method Channel在Flutter中获取iPad「关于」页面的用户自定义设备名,该方案在iOS16以下版本的iPad上运行正常,但在iOS16及以上版本无法生效。以下是当前实现的代码:
iOS端Swift代码
import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Register Flutter plugins GeneratedPluginRegistrant.register(with: self) // Set up a platform channel to fetch device name let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let deviceInfoChannel = FlutterMethodChannel(name: "device_info", binaryMessenger: controller.binaryMessenger) deviceInfoChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in guard call.method == "getDeviceName" else { result(FlutterMethodNotImplemented) return } let deviceName = self?.getCustomDeviceName() result(deviceName) }) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } func getCustomDeviceName() -> String { var deviceName: String? // Fetch device name from UserDefaults if let deviceNameValue = UserDefaults.standard.string(forKey: "DeviceName") { deviceName = deviceNameValue } // If device name not found in UserDefaults, use the default device name if deviceName == nil || deviceName!.isEmpty { deviceName = UIDevice.current.name } return deviceName! } }
Flutter端页面代码
import 'dart:async'; import 'dart:developer'; import 'dart:io' show Platform; import 'package:device_id/service/device_name_finder.dart'; import 'package:flutter/material.dart'; class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { var actualDeviceName = ''; @override void initState() { super.initState(); findDeviceName(); // readIos(); } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Center( child: Padding( padding: const EdgeInsets.all(12.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Device Name : $actualDeviceName', textAlign: TextAlign.center, ), const SizedBox( height: 20, ), ElevatedButton( onPressed: () { setState(() { findDeviceName(); }); }, child: const Text('Check Device'), ), ], ), ), ), ), ); } Future<void> findDeviceName() async { if (Platform.isAndroid) { actualDeviceName = (await AndroidDeviceInformation.getDeviceName())!; setState(() {}); log("The Device name is $actualDeviceName"); } else if (Platform.isIOS) { actualDeviceName = (await IosDeviceInformation.getDeviceName())!; setState(() {}); log("The Device name is $actualDeviceName"); } } }
Method Channel管理类
import 'package:flutter/services.dart'; class IosDeviceInformation { static const MethodChannel _channel = MethodChannel('device_info'); static Future<String?> getDeviceName() async { try { return await _channel.invokeMethod('getDeviceName'); } on PlatformException catch (e) { print("Failed to get device name: '${e.message}'."); return null; } } } class AndroidDeviceInformation { static const MethodChannel _channel = MethodChannel('android_device_info'); static Future<String?> getDeviceName() async { try { return await _channel.invokeMethod('getDeviceName'); } on PlatformException catch (e) { print("Failed to get device name: '${e.message}'."); return null; } } }
请问如何修改该方案,使其能在iOS16+的iPad设备上正常工作?
解决方案
iOS16及以上版本中,UIDevice.current.name不会自动同步用户在「关于」页面修改的设备名,且存在缓存旧值的问题。需要通过以下修改适配iOS16+:
修改点说明
- 替换设备名获取API:使用
NSHost.current().name替代UIDevice.current.name,该API在iOS16+能实时获取最新的自定义设备名。 - 监听设备名变更通知:注册
UIDevice.nameDidChangeNotification通知,当用户修改设备名时自动更新本地存储的设备名,确保后续获取的是最新值。 - 优化本地存储逻辑:优先获取系统最新设备名,再结合本地存储做 fallback,避免缓存旧值。
修改后的iOS端Swift代码
import UIKit import Flutter import Foundation @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Register Flutter plugins GeneratedPluginRegistrant.register(with: self) // Set up a platform channel to fetch device name let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let deviceInfoChannel = FlutterMethodChannel(name: "device_info", binaryMessenger: controller.binaryMessenger) deviceInfoChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in guard call.method == "getDeviceName" else { result(FlutterMethodNotImplemented) return } let deviceName = self?.getCustomDeviceName() result(deviceName) }) // 监听设备名变更通知 NotificationCenter.default.addObserver( self, selector: #selector(deviceNameDidChange), name: UIDevice.nameDidChangeNotification, object: nil ) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } @objc private func deviceNameDidChange() { // 设备名变更时更新UserDefaults if let newName = getSystemDeviceName() { UserDefaults.standard.set(newName, forKey: "DeviceName") } } private func getSystemDeviceName() -> String? { // iOS16+ 使用NSHost获取最新设备名,兼容旧版本用UIDevice if #available(iOS 16.0, *) { return NSHost.current().name } else { return UIDevice.current.name } } func getCustomDeviceName() -> String { // 优先获取系统最新设备名,避免缓存旧值 var deviceName = getSystemDeviceName() // 如果系统获取失败,再尝试从本地存储读取 if deviceName == nil || deviceName!.isEmpty { deviceName = UserDefaults.standard.string(forKey: "DeviceName") } // 最后 fallback 到UIDevice默认值(兼容极低版本) if deviceName == nil || deviceName!.isEmpty { deviceName = UIDevice.current.name } return deviceName! } deinit { // 移除通知监听 NotificationCenter.default.removeObserver(self) } }
其他说明
- Flutter端和Method Channel管理类无需修改,保持原有逻辑即可。
- 测试时需在iPad的「设置-通用-关于」中修改设备名,点击Flutter页面的「Check Device」按钮验证是否获取到最新名称。
内容的提问来源于stack exchange,提问作者Rafi
相关产品推荐
相关产品推荐

