Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
6cc80082
Unverified
Commit
6cc80082
authored
Aug 31, 2018
by
Mikkel Nygaard Ravn
Committed by
GitHub
Aug 31, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix extraction of product bundle ID for iOS projects (#21252)
parent
f999f144
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
96 additions
and
7 deletions
+96
-7
application_package.dart
packages/flutter_tools/lib/src/application_package.dart
+1
-1
build_ios.dart
packages/flutter_tools/lib/src/commands/build_ios.dart
+1
-1
plist_utils.dart
packages/flutter_tools/lib/src/ios/plist_utils.dart
+4
-2
xcodeproj.dart
packages/flutter_tools/lib/src/ios/xcodeproj.dart
+1
-1
project.dart
packages/flutter_tools/lib/src/project.dart
+30
-2
project_test.dart
packages/flutter_tools/test/project_test.dart
+59
-0
No files found.
packages/flutter_tools/lib/src/application_package.dart
View file @
6cc80082
...
@@ -34,7 +34,7 @@ abstract class ApplicationPackage {
...
@@ -34,7 +34,7 @@ abstract class ApplicationPackage {
File
get
packagesFile
=>
null
;
File
get
packagesFile
=>
null
;
@override
@override
String
toString
()
=>
displayName
;
String
toString
()
=>
displayName
??
id
;
}
}
class
AndroidApk
extends
ApplicationPackage
{
class
AndroidApk
extends
ApplicationPackage
{
...
...
packages/flutter_tools/lib/src/commands/build_ios.dart
View file @
6cc80082
...
@@ -78,7 +78,7 @@ class BuildIOSCommand extends BuildSubCommand {
...
@@ -78,7 +78,7 @@ class BuildIOSCommand extends BuildSubCommand {
final
String
logTarget
=
forSimulator
?
'simulator'
:
'device'
;
final
String
logTarget
=
forSimulator
?
'simulator'
:
'device'
;
final
String
typeName
=
artifacts
.
getEngineType
(
TargetPlatform
.
ios
,
buildInfo
.
mode
);
final
String
typeName
=
artifacts
.
getEngineType
(
TargetPlatform
.
ios
,
buildInfo
.
mode
);
printStatus
(
'Building
$
{app.toString()}
for
$logTarget
(
$typeName
)...'
);
printStatus
(
'Building
$
app
for
$logTarget
(
$typeName
)...'
);
final
XcodeBuildResult
result
=
await
buildXcodeProject
(
final
XcodeBuildResult
result
=
await
buildXcodeProject
(
app:
app
,
app:
app
,
buildInfo:
buildInfo
,
buildInfo:
buildInfo
,
...
...
packages/flutter_tools/lib/src/ios/plist_utils.dart
View file @
6cc80082
...
@@ -16,7 +16,9 @@ String getValueFromFile(String plistFilePath, String key) {
...
@@ -16,7 +16,9 @@ String getValueFromFile(String plistFilePath, String key) {
// Don't use PlistBuddy since that is not guaranteed to be installed.
// Don't use PlistBuddy since that is not guaranteed to be installed.
// 'defaults' requires the path to be absolute and without the 'plist'
// 'defaults' requires the path to be absolute and without the 'plist'
// extension.
// extension.
const
String
executable
=
'/usr/bin/defaults'
;
if
(!
fs
.
isFileSync
(
executable
))
return
null
;
if
(!
fs
.
isFileSync
(
plistFilePath
))
if
(!
fs
.
isFileSync
(
plistFilePath
))
return
null
;
return
null
;
...
@@ -24,7 +26,7 @@ String getValueFromFile(String plistFilePath, String key) {
...
@@ -24,7 +26,7 @@ String getValueFromFile(String plistFilePath, String key) {
try
{
try
{
final
String
value
=
runCheckedSync
(<
String
>[
final
String
value
=
runCheckedSync
(<
String
>[
'/usr/bin/defaults'
,
'read'
,
normalizedPlistPath
,
key
executable
,
'read'
,
normalizedPlistPath
,
key
]);
]);
return
value
.
isEmpty
?
null
:
value
;
return
value
.
isEmpty
?
null
:
value
;
}
catch
(
error
)
{
}
catch
(
error
)
{
...
...
packages/flutter_tools/lib/src/ios/xcodeproj.dart
View file @
6cc80082
...
@@ -20,7 +20,7 @@ import '../globals.dart';
...
@@ -20,7 +20,7 @@ import '../globals.dart';
import
'../project.dart'
;
import
'../project.dart'
;
final
RegExp
_settingExpr
=
new
RegExp
(
r'(\w+)\s*=\s*(.*)$'
);
final
RegExp
_settingExpr
=
new
RegExp
(
r'(\w+)\s*=\s*(.*)$'
);
final
RegExp
_varExpr
=
new
RegExp
(
r'\$\((
.
*)\)'
);
final
RegExp
_varExpr
=
new
RegExp
(
r'\$\((
[^)]
*)\)'
);
String
flutterFrameworkDir
(
BuildMode
mode
)
{
String
flutterFrameworkDir
(
BuildMode
mode
)
{
return
fs
.
path
.
normalize
(
fs
.
path
.
dirname
(
artifacts
.
getArtifactPath
(
Artifact
.
flutterFramework
,
TargetPlatform
.
ios
,
mode
)));
return
fs
.
path
.
normalize
(
fs
.
path
.
dirname
(
artifacts
.
getArtifactPath
(
Artifact
.
flutterFramework
,
TargetPlatform
.
ios
,
mode
)));
...
...
packages/flutter_tools/lib/src/project.dart
View file @
6cc80082
...
@@ -13,6 +13,8 @@ import 'build_info.dart';
...
@@ -13,6 +13,8 @@ import 'build_info.dart';
import
'bundle.dart'
as
bundle
;
import
'bundle.dart'
as
bundle
;
import
'cache.dart'
;
import
'cache.dart'
;
import
'flutter_manifest.dart'
;
import
'flutter_manifest.dart'
;
import
'ios/ios_workflow.dart'
;
import
'ios/plist_utils.dart'
as
plist
;
import
'ios/xcodeproj.dart'
as
xcode
;
import
'ios/xcodeproj.dart'
as
xcode
;
import
'plugins.dart'
;
import
'plugins.dart'
;
import
'template.dart'
;
import
'template.dart'
;
...
@@ -147,6 +149,7 @@ class FlutterProject {
...
@@ -147,6 +149,7 @@ class FlutterProject {
/// Flutter applications and the `.ios/` sub-folder of Flutter modules.
/// Flutter applications and the `.ios/` sub-folder of Flutter modules.
class
IosProject
{
class
IosProject
{
static
final
RegExp
_productBundleIdPattern
=
new
RegExp
(
r'^\s*PRODUCT_BUNDLE_IDENTIFIER\s*=\s*(.*);\s*$'
);
static
final
RegExp
_productBundleIdPattern
=
new
RegExp
(
r'^\s*PRODUCT_BUNDLE_IDENTIFIER\s*=\s*(.*);\s*$'
);
static
const
String
_productBundleIdVariable
=
r'$(PRODUCT_BUNDLE_IDENTIFIER)'
;
static
const
String
_hostAppBundleName
=
'Runner'
;
static
const
String
_hostAppBundleName
=
'Runner'
;
IosProject
.
_
(
this
.
parent
);
IosProject
.
_
(
this
.
parent
);
...
@@ -174,22 +177,47 @@ class IosProject {
...
@@ -174,22 +177,47 @@ class IosProject {
/// The 'Manifest.lock'.
/// The 'Manifest.lock'.
File
get
podManifestLock
=>
directory
.
childDirectory
(
'Pods'
).
childFile
(
'Manifest.lock'
);
File
get
podManifestLock
=>
directory
.
childDirectory
(
'Pods'
).
childFile
(
'Manifest.lock'
);
/// The 'Info.plist' file of the host app.
File
get
hostInfoPlist
=>
directory
.
childDirectory
(
_hostAppBundleName
).
childFile
(
'Info.plist'
);
/// '.xcodeproj' folder of the host app.
/// '.xcodeproj' folder of the host app.
Directory
get
xcodeProject
=>
directory
.
childDirectory
(
'
$_hostAppBundleName
.xcodeproj'
);
Directory
get
xcodeProject
=>
directory
.
childDirectory
(
'
$_hostAppBundleName
.xcodeproj'
);
/// The '.pbxproj' file of the host app.
/// The '.pbxproj' file of the host app.
File
get
xcodeProjectInfoFile
=>
xcodeProject
.
childFile
(
'project.pbxproj'
);
File
get
xcodeProjectInfoFile
=>
xcodeProject
.
childFile
(
'project.pbxproj'
);
/// The product bundle identifier of the host app.
/// The product bundle identifier of the host app, or null if not set or if
/// iOS tooling needed to read it is not installed.
String
get
productBundleIdentifier
{
String
get
productBundleIdentifier
{
return
_firstMatchInFile
(
xcodeProjectInfoFile
,
_productBundleIdPattern
)?.
group
(
1
);
final
String
fromPlist
=
iosWorkflow
.
getPlistValueFromFile
(
hostInfoPlist
.
path
,
plist
.
kCFBundleIdentifierKey
,
);
if
(
fromPlist
!=
null
&&
!
fromPlist
.
contains
(
'
\$
'
))
{
// Info.plist has no build variables in product bundle ID.
return
fromPlist
;
}
final
String
fromPbxproj
=
_firstMatchInFile
(
xcodeProjectInfoFile
,
_productBundleIdPattern
)?.
group
(
1
);
if
(
fromPbxproj
!=
null
&&
(
fromPlist
==
null
||
fromPlist
==
_productBundleIdVariable
))
{
// Common case. Avoids parsing build settings.
return
fromPbxproj
;
}
if
(
fromPlist
!=
null
&&
xcode
.
xcodeProjectInterpreter
.
isInstalled
)
{
// General case: perform variable substitution using build settings.
return
xcode
.
substituteXcodeVariables
(
fromPlist
,
buildSettings
);
}
return
null
;
}
}
/// True, if the host app project is using Swift.
/// True, if the host app project is using Swift.
bool
get
isSwift
=>
buildSettings
?.
containsKey
(
'SWIFT_VERSION'
);
bool
get
isSwift
=>
buildSettings
?.
containsKey
(
'SWIFT_VERSION'
);
/// The build settings for the host app of this project, as a detached map.
/// The build settings for the host app of this project, as a detached map.
///
/// Returns null, if iOS tooling is unavailable.
Map
<
String
,
String
>
get
buildSettings
{
Map
<
String
,
String
>
get
buildSettings
{
if
(!
xcode
.
xcodeProjectInterpreter
.
isInstalled
)
return
null
;
return
xcode
.
xcodeProjectInterpreter
.
getBuildSettings
(
xcodeProject
.
path
,
_hostAppBundleName
);
return
xcode
.
xcodeProjectInterpreter
.
getBuildSettings
(
xcodeProject
.
path
,
_hostAppBundleName
);
}
}
...
...
packages/flutter_tools/test/project_test.dart
View file @
6cc80082
...
@@ -9,10 +9,13 @@ import 'package:flutter_tools/src/base/context.dart';
...
@@ -9,10 +9,13 @@ import 'package:flutter_tools/src/base/context.dart';
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/flutter_manifest.dart'
;
import
'package:flutter_tools/src/flutter_manifest.dart'
;
import
'package:flutter_tools/src/ios/ios_workflow.dart'
;
import
'package:flutter_tools/src/ios/xcodeproj.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:file/file.dart'
;
import
'package:file/file.dart'
;
import
'package:file/memory.dart'
;
import
'package:file/memory.dart'
;
import
'package:mockito/mockito.dart'
;
import
'src/common.dart'
;
import
'src/common.dart'
;
import
'src/context.dart'
;
import
'src/context.dart'
;
...
@@ -221,6 +224,55 @@ void main() {
...
@@ -221,6 +224,55 @@ void main() {
});
});
});
});
group
(
'product bundle identifier'
,
()
{
MemoryFileSystem
fs
;
MockIOSWorkflow
mockIOSWorkflow
;
MockXcodeProjectInterpreter
mockXcodeProjectInterpreter
;
setUp
(()
{
fs
=
new
MemoryFileSystem
();
mockIOSWorkflow
=
new
MockIOSWorkflow
();
mockXcodeProjectInterpreter
=
new
MockXcodeProjectInterpreter
();
});
void
testWithMocks
(
String
description
,
Future
<
Null
>
testMethod
())
{
testUsingContext
(
description
,
testMethod
,
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
IOSWorkflow:
()
=>
mockIOSWorkflow
,
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
});
}
testWithMocks
(
'null, if no pbxproj or plist entries'
,
()
async
{
final
FlutterProject
project
=
await
someProject
();
expect
(
project
.
ios
.
productBundleIdentifier
,
isNull
);
});
testWithMocks
(
'from pbxproj file, if no plist'
,
()
async
{
final
FlutterProject
project
=
await
someProject
();
addIosWithBundleId
(
project
.
directory
,
'io.flutter.someProject'
);
expect
(
project
.
ios
.
productBundleIdentifier
,
'io.flutter.someProject'
);
});
testWithMocks
(
'from plist, if no variables'
,
()
async
{
final
FlutterProject
project
=
await
someProject
();
when
(
mockIOSWorkflow
.
getPlistValueFromFile
(
any
,
any
)).
thenReturn
(
'io.flutter.someProject'
);
expect
(
project
.
ios
.
productBundleIdentifier
,
'io.flutter.someProject'
);
});
testWithMocks
(
'from pbxproj and plist, if default variable'
,
()
async
{
final
FlutterProject
project
=
await
someProject
();
addIosWithBundleId
(
project
.
directory
,
'io.flutter.someProject'
);
when
(
mockIOSWorkflow
.
getPlistValueFromFile
(
any
,
any
)).
thenReturn
(
'
\$
(PRODUCT_BUNDLE_IDENTIFIER)'
);
expect
(
project
.
ios
.
productBundleIdentifier
,
'io.flutter.someProject'
);
});
testWithMocks
(
'from pbxproj and plist, by substitution'
,
()
async
{
final
FlutterProject
project
=
await
someProject
();
when
(
mockXcodeProjectInterpreter
.
getBuildSettings
(
any
,
any
)).
thenReturn
(<
String
,
String
>{
'PRODUCT_BUNDLE_IDENTIFIER'
:
'io.flutter.someProject'
,
'SUFFIX'
:
'suffix'
,
});
when
(
mockIOSWorkflow
.
getPlistValueFromFile
(
any
,
any
)).
thenReturn
(
'
\$
(PRODUCT_BUNDLE_IDENTIFIER).
\$
(SUFFIX)'
);
expect
(
project
.
ios
.
productBundleIdentifier
,
'io.flutter.someProject.suffix'
);
});
});
group
(
'organization names set'
,
()
{
group
(
'organization names set'
,
()
{
testInMemory
(
'is empty, if project not created'
,
()
async
{
testInMemory
(
'is empty, if project not created'
,
()
async
{
final
FlutterProject
project
=
await
someProject
();
final
FlutterProject
project
=
await
someProject
();
...
@@ -457,3 +509,10 @@ File androidPluginRegistrant(Directory parent) {
...
@@ -457,3 +509,10 @@ File androidPluginRegistrant(Directory parent) {
.
childDirectory
(
'plugins'
)
.
childDirectory
(
'plugins'
)
.
childFile
(
'GeneratedPluginRegistrant.java'
);
.
childFile
(
'GeneratedPluginRegistrant.java'
);
}
}
class
MockIOSWorkflow
extends
Mock
implements
IOSWorkflow
{}
class
MockXcodeProjectInterpreter
extends
Mock
implements
XcodeProjectInterpreter
{
@override
bool
get
isInstalled
=>
true
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment