You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 19:17:15