Fixes null error when parsing universal link settings (#9581)
fixes https://github.com/flutter/devtools/issues/8972
it is possible the tool can't get team id from the xcode project if the xcode developer team is not properly set up. In that case it will be null in the universal link setting's json. This Pr handles that cases
![build.yaml badge]
If you need help, consider asking for help on [Discord].
[build.yaml badge]: https://github.com/flutter/devtools/actions/workflows/build.yaml/badge.svg
diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
index c691a04..1f193db 100644
--- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
+++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
@@ -55,6 +55,8 @@
- Added more informative dialog if Deep Links tool is unable to find build
options for the iOS or Android app. -
[#9571](https://github.com/flutter/devtools/pull/9571)
+- Fixed null error when parsing universal link settings -
+ [#9581](https://github.com/flutter/devtools/pull/9581)
## VS Code Sidebar updates
diff --git a/packages/devtools_shared/lib/src/deeplink/universal_link_settings.dart b/packages/devtools_shared/lib/src/deeplink/universal_link_settings.dart
index 486b09a..0cc78b5 100644
--- a/packages/devtools_shared/lib/src/deeplink/universal_link_settings.dart
+++ b/packages/devtools_shared/lib/src/deeplink/universal_link_settings.dart
@@ -21,10 +21,10 @@
});
/// The bundle identifier of the iOS build of this Flutter project.
- String get bundleIdentifier => _json[_kBundleIdentifierKey] as String;
+ String? get bundleIdentifier => _json[_kBundleIdentifierKey] as String?;
/// The team identifier of the iOS build of this Flutter project.
- String get teamIdentifier => _json[_kTeamIdentifierKey] as String;
+ String? get teamIdentifier => _json[_kTeamIdentifierKey] as String?;
/// The associated domains of the iOS build of this Flutter project.
List<String> get associatedDomains =>
diff --git a/packages/devtools_shared/test/deeplink/universal_link_settings_test.dart b/packages/devtools_shared/test/deeplink/universal_link_settings_test.dart
new file mode 100644
index 0000000..15a56ad
--- /dev/null
+++ b/packages/devtools_shared/test/deeplink/universal_link_settings_test.dart
@@ -0,0 +1,50 @@
+// Copyright 2025 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
+
+import 'package:devtools_shared/src/deeplink/universal_link_settings.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('UniversalLinkSettings', () {
+ test('parses json correctly', () {
+ const json = '''
+{
+ "bundleIdentifier": "com.example.app",
+ "teamIdentifier": "TEAMID",
+ "associatedDomains": ["applinks:example.com"]
+}
+''';
+ final settings = UniversalLinkSettings.fromJson(json);
+ expect(settings.bundleIdentifier, 'com.example.app');
+ expect(settings.teamIdentifier, 'TEAMID');
+ expect(settings.associatedDomains, ['applinks:example.com']);
+ });
+
+ test('handles null bundleIdentifier', () {
+ const json = '''
+{
+ "teamIdentifier": "TEAMID",
+ "associatedDomains": ["applinks:example.com"]
+}
+''';
+ final settings = UniversalLinkSettings.fromJson(json);
+ expect(settings.bundleIdentifier, isNull);
+ expect(settings.teamIdentifier, 'TEAMID');
+ expect(settings.associatedDomains, ['applinks:example.com']);
+ });
+
+ test('handles null teamIdentifier', () {
+ const json = '''
+{
+ "bundleIdentifier": "com.example.app",
+ "associatedDomains": ["applinks:example.com"]
+}
+''';
+ final settings = UniversalLinkSettings.fromJson(json);
+ expect(settings.bundleIdentifier, 'com.example.app');
+ expect(settings.teamIdentifier, isNull);
+ expect(settings.associatedDomains, ['applinks:example.com']);
+ });
+ });
+}