mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add observatory Bonjour service to built iOS Info.plist bundle (#65138)
This commit is contained in:
parent
c034f1a1cc
commit
5e0aa8b9fc
@ -14,8 +14,6 @@ import 'package:path/path.dart' as path;
|
||||
Future<void> main() async {
|
||||
await task(() async {
|
||||
try {
|
||||
bool foundProjectName = false;
|
||||
bool bitcode = false;
|
||||
await runProjectTest((FlutterProject flutterProject) async {
|
||||
section('Build app with with --obfuscate');
|
||||
await inDirectory(flutterProject.rootPath, () async {
|
||||
@ -52,6 +50,13 @@ Future<void> main() async {
|
||||
fail('Failed to produce expected output at ${outputAppFrameworkBinary.path}');
|
||||
}
|
||||
|
||||
if (await dartObservatoryBonjourServiceFound(outputAppPath)) {
|
||||
throw TaskResult.failure('Release bundle has unexpected NSBonjourServices');
|
||||
}
|
||||
if (await localNetworkUsageFound(outputAppPath)) {
|
||||
throw TaskResult.failure('Release bundle has unexpected NSLocalNetworkUsageDescription');
|
||||
}
|
||||
|
||||
section('Validate obfuscation');
|
||||
|
||||
// Verify that an identifier from the Dart project code is not present
|
||||
@ -63,11 +68,11 @@ Future<void> main() async {
|
||||
canFail: true,
|
||||
);
|
||||
if (response.trim().contains('matches')) {
|
||||
foundProjectName = true;
|
||||
throw TaskResult.failure('Found project name in obfuscated dart library');
|
||||
}
|
||||
});
|
||||
|
||||
section('Validate bitcode');
|
||||
section('Validate release contents');
|
||||
|
||||
final Directory outputFlutterFramework = Directory(path.join(
|
||||
flutterProject.rootPath,
|
||||
@ -83,7 +88,13 @@ Future<void> main() async {
|
||||
if (!outputFlutterFrameworkBinary.existsSync()) {
|
||||
fail('Failed to produce expected output at ${outputFlutterFrameworkBinary.path}');
|
||||
}
|
||||
bitcode = await containsBitcode(outputFlutterFrameworkBinary.path);
|
||||
|
||||
// Archiving should contain a bitcode blob, but not building in release.
|
||||
// This mimics Xcode behavior and present a developer from having to install a
|
||||
// 300+MB app to test devices.
|
||||
if (await containsBitcode(outputFlutterFrameworkBinary.path)) {
|
||||
throw TaskResult.failure('Bitcode present in Flutter.framework');
|
||||
}
|
||||
|
||||
section('Xcode backend script');
|
||||
|
||||
@ -101,7 +112,7 @@ Future<void> main() async {
|
||||
'xcode_backend.sh'
|
||||
);
|
||||
|
||||
// Simulate a commonly Xcode build setting misconfiguration
|
||||
// Simulate a common Xcode build setting misconfiguration
|
||||
// where FLUTTER_APPLICATION_PATH is missing
|
||||
final int result = await exec(
|
||||
xcodeBackendPath,
|
||||
@ -111,6 +122,7 @@ Future<void> main() async {
|
||||
'TARGET_BUILD_DIR': buildPath,
|
||||
'FRAMEWORKS_FOLDER_PATH': 'Runner.app/Frameworks',
|
||||
'VERBOSE_SCRIPT_LOGGING': '1',
|
||||
'FLUTTER_BUILD_MODE': 'release',
|
||||
'ACTION': 'install', // Skip bitcode stripping since we just checked that above.
|
||||
},
|
||||
);
|
||||
@ -126,17 +138,35 @@ Future<void> main() async {
|
||||
if (!outputAppFrameworkBinary.existsSync()) {
|
||||
fail('Failed to re-embed ${outputAppFrameworkBinary.path}');
|
||||
}
|
||||
});
|
||||
|
||||
if (foundProjectName) {
|
||||
return TaskResult.failure('Found project name in obfuscated dart library');
|
||||
}
|
||||
// Archiving should contain a bitcode blob, but not building in release.
|
||||
// This mimics Xcode behavior and present a developer from having to install a
|
||||
// 300+MB app to test devices.
|
||||
if (bitcode) {
|
||||
return TaskResult.failure('Bitcode present in Flutter.framework');
|
||||
}
|
||||
section('Clean build');
|
||||
|
||||
await inDirectory(flutterProject.rootPath, () async {
|
||||
await flutter('clean');
|
||||
});
|
||||
|
||||
section('Validate debug contents');
|
||||
|
||||
await inDirectory(flutterProject.rootPath, () async {
|
||||
await flutter('build', options: <String>[
|
||||
'ios',
|
||||
'--debug',
|
||||
'--no-codesign',
|
||||
]);
|
||||
});
|
||||
|
||||
// Debug should also not contain bitcode.
|
||||
if (await containsBitcode(outputFlutterFrameworkBinary.path)) {
|
||||
throw TaskResult.failure('Bitcode present in Flutter.framework');
|
||||
}
|
||||
|
||||
if (!await dartObservatoryBonjourServiceFound(outputAppPath)) {
|
||||
throw TaskResult.failure('Debug bundle is missing NSBonjourServices');
|
||||
}
|
||||
if (!await localNetworkUsageFound(outputAppPath)) {
|
||||
throw TaskResult.failure('Debug bundle is missing NSLocalNetworkUsageDescription');
|
||||
}
|
||||
});
|
||||
|
||||
return TaskResult.success(null);
|
||||
} on TaskResult catch (taskResult) {
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'utils.dart';
|
||||
|
||||
typedef SimulatorFunction = Future<void> Function(String deviceId);
|
||||
@ -102,6 +104,40 @@ Future<bool> containsBitcode(String pathToBinary) async {
|
||||
return !emptyBitcodeMarkerFound;
|
||||
}
|
||||
|
||||
Future<bool> dartObservatoryBonjourServiceFound(String appBundlePath) async =>
|
||||
(await eval(
|
||||
'plutil',
|
||||
<String>[
|
||||
'-extract',
|
||||
'NSBonjourServices',
|
||||
'xml1',
|
||||
'-o',
|
||||
'-',
|
||||
path.join(
|
||||
appBundlePath,
|
||||
'Info.plist',
|
||||
),
|
||||
],
|
||||
canFail: true,
|
||||
)).contains('_dartobservatory._tcp');
|
||||
|
||||
Future<bool> localNetworkUsageFound(String appBundlePath) async =>
|
||||
await exec(
|
||||
'plutil',
|
||||
<String>[
|
||||
'-extract',
|
||||
'NSLocalNetworkUsageDescription',
|
||||
'xml1',
|
||||
'-o',
|
||||
'-',
|
||||
path.join(
|
||||
appBundlePath,
|
||||
'Info.plist',
|
||||
),
|
||||
],
|
||||
canFail: true,
|
||||
) == 0;
|
||||
|
||||
/// Creates and boots a new simulator, passes the new simulator's identifier to
|
||||
/// `testFunction`.
|
||||
///
|
||||
|
||||
@ -38,6 +38,32 @@ AssertExists() {
|
||||
return 0
|
||||
}
|
||||
|
||||
ParseFlutterBuildMode() {
|
||||
# Use FLUTTER_BUILD_MODE if it's set, otherwise use the Xcode build configuration name
|
||||
# This means that if someone wants to use an Xcode build config other than Debug/Profile/Release,
|
||||
# they _must_ set FLUTTER_BUILD_MODE so we know what type of artifact to build.
|
||||
local build_mode="$(echo "${FLUTTER_BUILD_MODE:-${CONFIGURATION}}" | tr "[:upper:]" "[:lower:]")"
|
||||
|
||||
case "$build_mode" in
|
||||
*release*) build_mode="release";;
|
||||
*profile*) build_mode="profile";;
|
||||
*debug*) build_mode="debug";;
|
||||
*)
|
||||
EchoError "========================================================================"
|
||||
EchoError "ERROR: Unknown FLUTTER_BUILD_MODE: ${build_mode}."
|
||||
EchoError "Valid values are 'Debug', 'Profile', or 'Release' (case insensitive)."
|
||||
EchoError "This is controlled by the FLUTTER_BUILD_MODE environment variable."
|
||||
EchoError "If that is not set, the CONFIGURATION environment variable is used."
|
||||
EchoError ""
|
||||
EchoError "You can fix this by either adding an appropriately named build"
|
||||
EchoError "configuration, or adding an appropriate value for FLUTTER_BUILD_MODE to the"
|
||||
EchoError ".xcconfig file for the current build configuration (${CONFIGURATION})."
|
||||
EchoError "========================================================================"
|
||||
exit -1;;
|
||||
esac
|
||||
echo "${build_mode}"
|
||||
}
|
||||
|
||||
BuildApp() {
|
||||
local project_path="${SOURCE_ROOT}/.."
|
||||
if [[ -n "$FLUTTER_APPLICATION_PATH" ]]; then
|
||||
@ -72,24 +98,12 @@ BuildApp() {
|
||||
# Use FLUTTER_BUILD_MODE if it's set, otherwise use the Xcode build configuration name
|
||||
# This means that if someone wants to use an Xcode build config other than Debug/Profile/Release,
|
||||
# they _must_ set FLUTTER_BUILD_MODE so we know what type of artifact to build.
|
||||
local build_mode="$(echo "${FLUTTER_BUILD_MODE:-${CONFIGURATION}}" | tr "[:upper:]" "[:lower:]")"
|
||||
local build_mode="$(ParseFlutterBuildMode)"
|
||||
local artifact_variant="unknown"
|
||||
case "$build_mode" in
|
||||
*release*) build_mode="release"; artifact_variant="ios-release";;
|
||||
*profile*) build_mode="profile"; artifact_variant="ios-profile";;
|
||||
*debug*) build_mode="debug"; artifact_variant="ios";;
|
||||
*)
|
||||
EchoError "========================================================================"
|
||||
EchoError "ERROR: Unknown FLUTTER_BUILD_MODE: ${build_mode}."
|
||||
EchoError "Valid values are 'Debug', 'Profile', or 'Release' (case insensitive)."
|
||||
EchoError "This is controlled by the FLUTTER_BUILD_MODE environment variable."
|
||||
EchoError "If that is not set, the CONFIGURATION environment variable is used."
|
||||
EchoError ""
|
||||
EchoError "You can fix this by either adding an appropriately named build"
|
||||
EchoError "configuration, or adding an appropriate value for FLUTTER_BUILD_MODE to the"
|
||||
EchoError ".xcconfig file for the current build configuration (${CONFIGURATION})."
|
||||
EchoError "========================================================================"
|
||||
exit -1;;
|
||||
release ) artifact_variant="ios-release";;
|
||||
profile ) artifact_variant="ios-profile";;
|
||||
debug ) artifact_variant="ios";;
|
||||
esac
|
||||
|
||||
# Warn the user if not archiving (ACTION=install) in release mode.
|
||||
@ -127,7 +141,7 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr
|
||||
fi
|
||||
|
||||
local bitcode_flag=""
|
||||
if [[ $ENABLE_BITCODE == "YES" ]]; then
|
||||
if [[ "$ENABLE_BITCODE" == "YES" ]]; then
|
||||
bitcode_flag="true"
|
||||
fi
|
||||
|
||||
@ -306,6 +320,36 @@ EmbedFlutterFrameworks() {
|
||||
RunCommand codesign --force --verbose --sign "${EXPANDED_CODE_SIGN_IDENTITY}" -- "${xcode_frameworks_dir}/App.framework/App"
|
||||
RunCommand codesign --force --verbose --sign "${EXPANDED_CODE_SIGN_IDENTITY}" -- "${xcode_frameworks_dir}/Flutter.framework/Flutter"
|
||||
fi
|
||||
|
||||
AddObservatoryBonjourService
|
||||
}
|
||||
|
||||
# Add the observatory publisher Bonjour service to the produced app bundle Info.plist.
|
||||
AddObservatoryBonjourService() {
|
||||
local build_mode="$(ParseFlutterBuildMode)"
|
||||
# Debug and profile only.
|
||||
if [[ "${build_mode}" == "release" ]]; then
|
||||
return
|
||||
fi
|
||||
local built_products_plist="${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}"
|
||||
|
||||
if [[ ! -f "${built_products_plist}" ]]; then
|
||||
EchoError "error: ${INFOPLIST_PATH} does not exist. The Flutter \"Thin Binary\" build phase must run after \"Copy Bundle Resources\"."
|
||||
exit -1
|
||||
fi
|
||||
# If there are already NSBonjourServices specified by the app (uncommon), insert the observatory service name to the existing list.
|
||||
if plutil -extract NSBonjourServices xml1 -o - "${built_products_plist}"; then
|
||||
RunCommand plutil -insert NSBonjourServices.0 -string "_dartobservatory._tcp" "${built_products_plist}"
|
||||
else
|
||||
# Otherwise, add the NSBonjourServices key and observatory service name.
|
||||
RunCommand plutil -insert NSBonjourServices -json "[\"_dartobservatory._tcp\"]" "${built_products_plist}"
|
||||
fi
|
||||
|
||||
# Don't override the local network description the Flutter app developer specified (uncommon).
|
||||
# This text will appear below the "Your app would like to find and connect to devices on your local network" permissions popup.
|
||||
if ! plutil -extract NSLocalNetworkUsageDescription xml1 -o - "${built_products_plist}"; then
|
||||
RunCommand plutil -insert NSLocalNetworkUsageDescription -string "Allow Flutter tools on your computer to connect and debug your application. This prompt will not appear on release builds." "${built_products_plist}"
|
||||
fi
|
||||
}
|
||||
|
||||
EmbedAndThinFrameworks() {
|
||||
@ -328,5 +372,8 @@ else
|
||||
EmbedFlutterFrameworks ;;
|
||||
"embed_and_thin")
|
||||
EmbedAndThinFrameworks ;;
|
||||
"test_observatory_bonjour_service")
|
||||
# Exposed for integration testing only.
|
||||
AddObservatoryBonjourService ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
|
||||
const String xcodeBackendPath = 'bin/xcode_backend.sh';
|
||||
const String xcodeBackendErrorHeader = '========================================================================';
|
||||
|
||||
// Acceptable $CONFIGURATION/$FLUTTER_BUILD_MODE values should be debug, profile, or release
|
||||
const Map<String, String> unknownConfiguration = <String, String>{
|
||||
'CONFIGURATION': 'Custom',
|
||||
};
|
||||
|
||||
// $FLUTTER_BUILD_MODE will override $CONFIGURATION
|
||||
const Map<String, String> unknownFlutterBuildMode = <String, String>{
|
||||
'FLUTTER_BUILD_MODE': 'Custom',
|
||||
'CONFIGURATION': 'Debug',
|
||||
};
|
||||
|
||||
// Can't archive a non-release build.
|
||||
const Map<String, String> installWithoutRelease = <String, String>{
|
||||
'CONFIGURATION': 'Debug',
|
||||
'ACTION': 'install',
|
||||
};
|
||||
|
||||
// Can't use a debug engine build with a release build.
|
||||
const Map<String, String> localEngineDebugBuildModeRelease = <String, String>{
|
||||
'SOURCE_ROOT': '../../../examples/hello_world',
|
||||
'FLUTTER_ROOT': '../../..',
|
||||
'LOCAL_ENGINE': '/engine/src/out/ios_debug_unopt',
|
||||
'CONFIGURATION': 'Release',
|
||||
};
|
||||
|
||||
// Can't use a debug build with a profile engine.
|
||||
const Map<String, String> localEngineProfileBuildeModeRelease = <String, String>{
|
||||
'SOURCE_ROOT': '../../../examples/hello_world',
|
||||
'FLUTTER_ROOT': '../../..',
|
||||
'LOCAL_ENGINE': '/engine/src/out/ios_profile',
|
||||
'CONFIGURATION': 'Debug',
|
||||
'FLUTTER_BUILD_MODE': 'Debug',
|
||||
};
|
||||
|
||||
void main() {
|
||||
Future<void> expectXcodeBackendFails(Map<String, String> environment) async {
|
||||
final ProcessResult result = await Process.run(
|
||||
xcodeBackendPath,
|
||||
<String>['build'],
|
||||
environment: environment,
|
||||
);
|
||||
expect(result.stderr, startsWith(xcodeBackendErrorHeader));
|
||||
expect(result.exitCode, isNot(0));
|
||||
}
|
||||
|
||||
test('Xcode backend fails for on unsupported configuration combinations', () async {
|
||||
await expectXcodeBackendFails(unknownConfiguration);
|
||||
await expectXcodeBackendFails(unknownFlutterBuildMode);
|
||||
await expectXcodeBackendFails(installWithoutRelease);
|
||||
await expectXcodeBackendFails(localEngineDebugBuildModeRelease);
|
||||
await expectXcodeBackendFails(localEngineProfileBuildeModeRelease);
|
||||
}, skip: true); // https://github.com/flutter/flutter/issues/35707 (non-hermetic test requires precache to have run)
|
||||
}
|
||||
@ -0,0 +1,206 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io' as io;
|
||||
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
|
||||
import '../src/common.dart';
|
||||
|
||||
const String xcodeBackendPath = 'bin/xcode_backend.sh';
|
||||
const String xcodeBackendErrorHeader = '========================================================================';
|
||||
|
||||
// Acceptable $CONFIGURATION/$FLUTTER_BUILD_MODE values should be debug, profile, or release
|
||||
const Map<String, String> unknownConfiguration = <String, String>{
|
||||
'CONFIGURATION': 'Custom',
|
||||
};
|
||||
|
||||
// $FLUTTER_BUILD_MODE will override $CONFIGURATION
|
||||
const Map<String, String> unknownFlutterBuildMode = <String, String>{
|
||||
'FLUTTER_BUILD_MODE': 'Custom',
|
||||
'CONFIGURATION': 'Debug',
|
||||
};
|
||||
|
||||
// Can't use a debug engine build with a release build.
|
||||
const Map<String, String> localEngineDebugBuildModeRelease = <String, String>{
|
||||
'SOURCE_ROOT': '../examples/hello_world',
|
||||
'FLUTTER_ROOT': '../..',
|
||||
'LOCAL_ENGINE': '/engine/src/out/ios_debug_unopt',
|
||||
'CONFIGURATION': 'Release',
|
||||
};
|
||||
|
||||
// Can't use a debug build with a profile engine.
|
||||
const Map<String, String> localEngineProfileBuildeModeRelease = <String, String>{
|
||||
'SOURCE_ROOT': '../examples/hello_world',
|
||||
'FLUTTER_ROOT': '../..',
|
||||
'LOCAL_ENGINE': '/engine/src/out/ios_profile',
|
||||
'CONFIGURATION': 'Debug',
|
||||
'FLUTTER_BUILD_MODE': 'Debug',
|
||||
};
|
||||
|
||||
void main() {
|
||||
Future<void> expectXcodeBackendFails(Map<String, String> environment) async {
|
||||
final ProcessResult result = await Process.run(
|
||||
xcodeBackendPath,
|
||||
<String>['build'],
|
||||
environment: environment,
|
||||
);
|
||||
expect(result.stderr, startsWith(xcodeBackendErrorHeader));
|
||||
expect(result.exitCode, isNot(0));
|
||||
}
|
||||
|
||||
test('Xcode backend fails with no arguments', () async {
|
||||
final ProcessResult result = await Process.run(
|
||||
xcodeBackendPath,
|
||||
<String>[],
|
||||
environment: <String, String>{
|
||||
'SOURCE_ROOT': '../examples/hello_world',
|
||||
'FLUTTER_ROOT': '../..',
|
||||
},
|
||||
);
|
||||
expect(result.stderr, startsWith('error: Your Xcode project is incompatible with this version of Flutter.'));
|
||||
expect(result.exitCode, isNot(0));
|
||||
}, skip: !io.Platform.isMacOS);
|
||||
|
||||
test('Xcode backend fails for on unsupported configuration combinations', () async {
|
||||
await expectXcodeBackendFails(unknownConfiguration);
|
||||
await expectXcodeBackendFails(unknownFlutterBuildMode);
|
||||
await expectXcodeBackendFails(localEngineDebugBuildModeRelease);
|
||||
await expectXcodeBackendFails(localEngineProfileBuildeModeRelease);
|
||||
}, skip: !io.Platform.isMacOS);
|
||||
|
||||
test('Xcode backend warns archiving a non-release build.', () async {
|
||||
final ProcessResult result = await Process.run(
|
||||
xcodeBackendPath,
|
||||
<String>['build'],
|
||||
environment: <String, String>{
|
||||
'CONFIGURATION': 'Debug',
|
||||
'ACTION': 'install',
|
||||
},
|
||||
);
|
||||
expect(result.stdout, contains('warning: Flutter archive not built in Release mode.'));
|
||||
expect(result.exitCode, isNot(0));
|
||||
}, skip: !io.Platform.isMacOS);
|
||||
|
||||
group('observatory Bonjour service keys', () {
|
||||
Directory buildDirectory;
|
||||
File infoPlist;
|
||||
|
||||
setUp(() {
|
||||
buildDirectory = globals.fs.systemTempDirectory.createTempSync('flutter_tools_xcode_backend_test.');
|
||||
infoPlist = buildDirectory.childFile('Info.plist');
|
||||
});
|
||||
|
||||
test('fails when the Info.plist is missing', () async {
|
||||
final ProcessResult result = await Process.run(
|
||||
xcodeBackendPath,
|
||||
<String>['test_observatory_bonjour_service'],
|
||||
environment: <String, String>{
|
||||
'CONFIGURATION': 'Debug',
|
||||
'BUILT_PRODUCTS_DIR': buildDirectory.path,
|
||||
'INFOPLIST_PATH': 'Info.plist',
|
||||
},
|
||||
);
|
||||
expect(result.stderr, startsWith('error: Info.plist does not exist.'));
|
||||
expect(result.exitCode, isNot(0));
|
||||
});
|
||||
|
||||
const String emptyPlist = '''
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
</dict>
|
||||
</plist>''';
|
||||
|
||||
test('does not add keys in Release', () async {
|
||||
infoPlist.writeAsStringSync(emptyPlist);
|
||||
|
||||
final ProcessResult result = await Process.run(
|
||||
xcodeBackendPath,
|
||||
<String>['test_observatory_bonjour_service'],
|
||||
environment: <String, String>{
|
||||
'CONFIGURATION': 'Release',
|
||||
'BUILT_PRODUCTS_DIR': buildDirectory.path,
|
||||
'INFOPLIST_PATH': 'Info.plist',
|
||||
},
|
||||
);
|
||||
|
||||
final String actualInfoPlist = infoPlist.readAsStringSync();
|
||||
expect(actualInfoPlist, isNot(contains('NSBonjourServices')));
|
||||
expect(actualInfoPlist, isNot(contains('dartobservatory')));
|
||||
expect(actualInfoPlist, isNot(contains('NSLocalNetworkUsageDescription')));
|
||||
|
||||
expect(result.exitCode, 0);
|
||||
});
|
||||
|
||||
for (final String buildConfiguration in <String>['Debug', 'Profile']) {
|
||||
test('add keys in $buildConfiguration', () async {
|
||||
infoPlist.writeAsStringSync(emptyPlist);
|
||||
|
||||
final ProcessResult result = await Process.run(
|
||||
xcodeBackendPath,
|
||||
<String>['test_observatory_bonjour_service'],
|
||||
environment: <String, String>{
|
||||
'CONFIGURATION': buildConfiguration,
|
||||
'BUILT_PRODUCTS_DIR': buildDirectory.path,
|
||||
'INFOPLIST_PATH': 'Info.plist',
|
||||
},
|
||||
);
|
||||
|
||||
final String actualInfoPlist = infoPlist.readAsStringSync();
|
||||
expect(actualInfoPlist, contains('NSBonjourServices'));
|
||||
expect(actualInfoPlist, contains('dartobservatory'));
|
||||
expect(actualInfoPlist, contains('NSLocalNetworkUsageDescription'));
|
||||
|
||||
expect(result.exitCode, 0);
|
||||
});
|
||||
}
|
||||
|
||||
test('adds to existing Bonjour services, does not override network usage description', () async {
|
||||
infoPlist.writeAsStringSync('''
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_bogus._tcp</string>
|
||||
</array>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Don't override this</string>
|
||||
</dict>
|
||||
</plist>''');
|
||||
|
||||
final ProcessResult result = await Process.run(
|
||||
xcodeBackendPath,
|
||||
<String>['test_observatory_bonjour_service'],
|
||||
environment: <String, String>{
|
||||
'CONFIGURATION': 'Debug',
|
||||
'BUILT_PRODUCTS_DIR': buildDirectory.path,
|
||||
'INFOPLIST_PATH': 'Info.plist',
|
||||
},
|
||||
);
|
||||
|
||||
expect(infoPlist.readAsStringSync(), '''
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_dartobservatory._tcp</string>
|
||||
<string>_bogus._tcp</string>
|
||||
</array>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Don't override this</string>
|
||||
</dict>
|
||||
</plist>
|
||||
''');
|
||||
expect(result.exitCode, 0);
|
||||
});
|
||||
}, skip: !io.Platform.isMacOS);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user