Support Xcode variable substitution in Info.plist
As of Xcode 7, Apple recommends setting CFBundleIdentifier to
$(PRODUCT_BUNDLE_IDENTIFIER).
diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart
index 29e374b..cf8ae2b 100644
--- a/packages/flutter_tools/lib/src/application_package.dart
+++ b/packages/flutter_tools/lib/src/application_package.dart
@@ -12,6 +12,7 @@
import 'build_info.dart';
import 'globals.dart';
import 'ios/plist_utils.dart';
+import 'ios/xcodeproj.dart';
abstract class ApplicationPackage {
/// Package ID from the Android Manifest or equivalent.
@@ -137,6 +138,8 @@
String value = getValueFromFile(plistPath, kCFBundleIdentifierKey);
if (value == null)
return null;
+ String projectPath = path.join('ios', 'Runner.xcodeproj');
+ value = substituteXcodeVariables(value, projectPath, 'Runner');
return new IOSApp(
appDirectory: path.join('ios'),
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 78df9a2..d180827 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -15,7 +15,7 @@
import '../flx.dart' as flx;
import '../globals.dart';
import '../services.dart';
-import 'setup_xcodeproj.dart';
+import 'xcodeproj.dart';
String get homeDirectory => path.absolute(Platform.environment['HOME']);
diff --git a/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
similarity index 62%
rename from packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart
rename to packages/flutter_tools/lib/src/ios/xcodeproj.dart
index 507b70c..6d1bc49 100644
--- a/packages/flutter_tools/lib/src/ios/setup_xcodeproj.dart
+++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
@@ -6,10 +6,14 @@
import 'package:path/path.dart' as path;
+import '../base/process.dart';
import '../build_info.dart';
import '../cache.dart';
import '../globals.dart';
+final RegExp _settingExpr = new RegExp(r'(\w+)\s*=\s*(\S+)');
+final RegExp _varExpr = new RegExp(r'\$\((.*)\)');
+
void updateXcodeGeneratedProperties(String projectPath, BuildMode mode, String target) {
StringBuffer localsBuffer = new StringBuffer();
@@ -43,3 +47,28 @@
localsFile.createSync(recursive: true);
localsFile.writeAsStringSync(localsBuffer.toString());
}
+
+Map<String, String> getXcodeBuildSettings(String xcodeProjPath, String target) {
+ String absProjPath = path.absolute(xcodeProjPath);
+ String out = runCheckedSync(<String>[
+ '/usr/bin/xcodebuild', '-project', absProjPath, '-target', target, '-showBuildSettings'
+ ]);
+ Map<String, String> settings = <String, String>{};
+ for (String line in out.split('\n').where(_settingExpr.hasMatch)) {
+ Match match = _settingExpr.firstMatch(line);
+ settings[match[1]] = match[2];
+ }
+ return settings;
+}
+
+
+/// Substitutes variables in [str] with their values from the specified Xcode
+/// project and target.
+String substituteXcodeVariables(String str, String xcodeProjPath, String target) {
+ Iterable<Match> matches = _varExpr.allMatches(str);
+ if (matches.isEmpty)
+ return str;
+
+ Map<String, String> settings = getXcodeBuildSettings(xcodeProjPath, target);
+ return str.replaceAllMapped(_varExpr, (Match m) => settings[m[1]] ?? m[0]);
+}