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
9383466d
Commit
9383466d
authored
Mar 10, 2016
by
Yegor Jbanov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[ios] look for the best available devicetype/runtime when booting
parent
e855c71f
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
216 additions
and
11 deletions
+216
-11
simulators.dart
packages/flutter_tools/lib/src/ios/simulators.dart
+162
-11
simulators_test.dart
packages/flutter_tools/test/src/ios/simulators_test.dart
+54
-0
No files found.
packages/flutter_tools/lib/src/ios/simulators.dart
View file @
9383466d
...
@@ -21,6 +21,9 @@ import 'mac.dart';
...
@@ -21,6 +21,9 @@ import 'mac.dart';
const
String
_xcrunPath
=
'/usr/bin/xcrun'
;
const
String
_xcrunPath
=
'/usr/bin/xcrun'
;
/// Test device created by Flutter when no other device is available.
const
String
_kFlutterTestDevice
=
'flutter.test.device'
;
class
IOSSimulators
extends
PollingDeviceDiscovery
{
class
IOSSimulators
extends
PollingDeviceDiscovery
{
IOSSimulators
()
:
super
(
'IOSSimulators'
);
IOSSimulators
()
:
super
(
'IOSSimulators'
);
...
@@ -49,16 +52,23 @@ class SimControl {
...
@@ -49,16 +52,23 @@ class SimControl {
/// Returns [SimControl] active in the current app context (i.e. zone).
/// Returns [SimControl] active in the current app context (i.e. zone).
static
SimControl
get
instance
=>
context
[
SimControl
]
??
(
context
[
SimControl
]
=
new
SimControl
());
static
SimControl
get
instance
=>
context
[
SimControl
]
??
(
context
[
SimControl
]
=
new
SimControl
());
Future
<
bool
>
boot
({
String
device
Id
})
async
{
Future
<
bool
>
boot
({
String
device
Name
})
async
{
if
(
_isAnyConnected
())
if
(
_isAnyConnected
())
return
true
;
return
true
;
if
(
deviceId
==
null
)
if
(
deviceName
==
null
)
{
deviceId
=
'iPhone 6 (9.2)'
;
SimDevice
testDevice
=
_createTestDevice
();
if
(
testDevice
==
null
)
{
return
false
;
}
deviceName
=
testDevice
.
name
;
}
// `xcrun instruments` requires a template (-t). @yjbanov has no idea what
// `xcrun instruments` requires a template (-t). @yjbanov has no idea what
// "template" is but the built-in 'Blank' seems to work.
// "template" is but the built-in 'Blank' seems to work. -l causes xcrun to
List
<
String
>
args
=
[
_xcrunPath
,
'instruments'
,
'-w'
,
deviceId
,
'-t'
,
'Blank'
];
// quit after a time limit without killing the simulator. We quit after
// 1 second.
List
<
String
>
args
=
[
_xcrunPath
,
'instruments'
,
'-w'
,
deviceName
,
'-t'
,
'Blank'
,
'-l'
,
'1'
];
printTrace
(
args
.
join
(
' '
));
printTrace
(
args
.
join
(
' '
));
runDetached
(
args
);
runDetached
(
args
);
printStatus
(
'Waiting for iOS Simulator to boot...'
);
printStatus
(
'Waiting for iOS Simulator to boot...'
);
...
@@ -83,9 +93,89 @@ class SimControl {
...
@@ -83,9 +93,89 @@ class SimControl {
}
}
}
}
/// Returns a list of all available devices, both potential and connected.
SimDevice
_createTestDevice
()
{
List
<
SimDevice
>
getDevices
()
{
String
deviceType
=
_findSuitableDeviceType
();
if
(
deviceType
==
null
)
{
return
null
;
}
String
runtime
=
_findSuitableRuntime
();
if
(
runtime
==
null
)
{
return
null
;
}
// Delete any old test devices
getDevices
()
.
where
((
d
)
=>
d
.
name
==
_kFlutterTestDevice
)
.
forEach
(
_deleteDevice
);
// Create new device
List
<
String
>
args
=
[
_xcrunPath
,
'simctl'
,
'create'
,
_kFlutterTestDevice
,
deviceType
,
runtime
];
printTrace
(
args
.
join
(
' '
));
runCheckedSync
(
args
);
return
getDevices
().
firstWhere
((
d
)
=>
d
.
name
==
_kFlutterTestDevice
);
}
String
_findSuitableDeviceType
()
{
List
<
Map
<
String
,
dynamic
>>
allTypes
=
_list
(
SimControlListSection
.
devicetypes
);
List
<
Map
<
String
,
dynamic
>>
usableTypes
=
allTypes
.
where
((
info
)
=>
info
[
'name'
].
startsWith
(
'iPhone'
))
.
toList
()
..
sort
((
r1
,
r2
)
=>
-
compareIphoneVersions
(
r1
[
'identifier'
],
r2
[
'identifier'
]));
if
(
usableTypes
.
isEmpty
)
{
printError
(
'No suitable device type found.'
'
\n
'
'You may launch an iOS Simulator manually and Flutter will attempt to '
'use it.'
);
}
return
usableTypes
.
first
[
'identifier'
];
}
String
_findSuitableRuntime
()
{
List
<
Map
<
String
,
dynamic
>>
allRuntimes
=
_list
(
SimControlListSection
.
runtimes
);
List
<
Map
<
String
,
dynamic
>>
usableRuntimes
=
allRuntimes
.
where
((
info
)
=>
info
[
'name'
].
startsWith
(
'iOS'
))
.
toList
()
..
sort
((
r1
,
r2
)
=>
-
compareIosVersions
(
r1
[
'version'
],
r2
[
'version'
]));
if
(
usableRuntimes
.
isEmpty
)
{
printError
(
'No suitable iOS runtime found.'
'
\n
'
'You may launch an iOS Simulator manually and Flutter will attempt to '
'use it.'
);
}
return
usableRuntimes
.
first
[
'identifier'
];
}
void
_deleteDevice
(
SimDevice
device
)
{
try
{
List
<
String
>
args
=
[
_xcrunPath
,
'simctl'
,
'delete'
,
device
.
name
];
printTrace
(
args
.
join
(
' '
));
runCheckedSync
(
args
);
}
catch
(
e
)
{
printError
(
e
);
}
}
/// Runs `simctl list --json` and returns the JSON of the corresponding
/// [section].
///
/// The return type depends on the [section] being listed but is usually
/// either a [Map] or a [List].
dynamic
_list
(
SimControlListSection
section
)
{
// Sample output from `simctl list --json`:
//
// {
// {
// "devicetypes": { ... },
// "runtimes": { ... },
// "devices" : {
// "devices" : {
// "com.apple.CoreSimulator.SimRuntime.iOS-8-2" : [
// "com.apple.CoreSimulator.SimRuntime.iOS-8-2" : [
// {
// {
...
@@ -95,19 +185,25 @@ class SimControl {
...
@@ -95,19 +185,25 @@ class SimControl {
// "udid" : "1913014C-6DCB-485D-AC6B-7CD76D322F5B"
// "udid" : "1913014C-6DCB-485D-AC6B-7CD76D322F5B"
// },
// },
// ...
// ...
// },
// "pairs": { ... },
List
<
String
>
args
=
<
String
>[
'simctl'
,
'list'
,
'--json'
,
'devices'
];
List
<
String
>
args
=
<
String
>[
'simctl'
,
'list'
,
'--json'
,
section
.
name
];
printTrace
(
'
$_xcrunPath
${args.join(' ')}
'
);
printTrace
(
'
$_xcrunPath
${args.join(' ')}
'
);
ProcessResult
results
=
Process
.
runSync
(
_xcrunPath
,
args
);
ProcessResult
results
=
Process
.
runSync
(
_xcrunPath
,
args
);
if
(
results
.
exitCode
!=
0
)
{
if
(
results
.
exitCode
!=
0
)
{
printError
(
'Error executing simctl:
${results.exitCode}
\n
${results.stderr}
'
);
printError
(
'Error executing simctl:
${results.exitCode}
\n
${results.stderr}
'
);
return
<
S
imDevice
>[]
;
return
<
S
tring
,
Map
<
String
,
dynamic
>>{}
;
}
}
return
JSON
.
decode
(
results
.
stdout
)[
section
.
name
];
}
/// Returns a list of all available devices, both potential and connected.
List
<
SimDevice
>
getDevices
()
{
List
<
SimDevice
>
devices
=
<
SimDevice
>[];
List
<
SimDevice
>
devices
=
<
SimDevice
>[];
Map
<
String
,
Map
<
String
,
dynamic
>>
data
=
JSON
.
decode
(
results
.
stdout
);
Map
<
String
,
dynamic
>
devicesSection
=
_list
(
SimControlListSection
.
devices
);
Map
<
String
,
dynamic
>
devicesSection
=
data
[
'devices'
];
for
(
String
deviceCategory
in
devicesSection
.
keys
)
{
for
(
String
deviceCategory
in
devicesSection
.
keys
)
{
List
<
dynamic
>
devicesData
=
devicesSection
[
deviceCategory
];
List
<
dynamic
>
devicesData
=
devicesSection
[
deviceCategory
];
...
@@ -192,6 +288,17 @@ class SimControl {
...
@@ -192,6 +288,17 @@ class SimControl {
}
}
}
}
/// Enumerates all data sections of `xcrun simctl list --json` command.
class
SimControlListSection
{
static
const
devices
=
const
SimControlListSection
.
_
(
'devices'
);
static
const
devicetypes
=
const
SimControlListSection
.
_
(
'devicetypes'
);
static
const
runtimes
=
const
SimControlListSection
.
_
(
'runtimes'
);
static
const
pairs
=
const
SimControlListSection
.
_
(
'pairs'
);
final
String
name
;
const
SimControlListSection
.
_
(
this
.
name
);
}
class
SimDevice
{
class
SimDevice
{
SimDevice
(
this
.
category
,
this
.
data
);
SimDevice
(
this
.
category
,
this
.
data
);
...
@@ -621,3 +728,47 @@ class _IOSSimulatorLogReader extends DeviceLogReader {
...
@@ -621,3 +728,47 @@ class _IOSSimulatorLogReader extends DeviceLogReader {
return
other
.
device
.
logFilePath
==
device
.
logFilePath
;
return
other
.
device
.
logFilePath
==
device
.
logFilePath
;
}
}
}
}
int
compareIosVersions
(
String
v1
,
String
v2
)
{
List
<
int
>
v1Fragments
=
v1
.
split
(
'.'
).
map
(
int
.
parse
).
toList
();
List
<
int
>
v2Fragments
=
v2
.
split
(
'.'
).
map
(
int
.
parse
).
toList
();
int
i
=
0
;
while
(
i
<
v1Fragments
.
length
&&
i
<
v2Fragments
.
length
)
{
int
v1Fragment
=
v1Fragments
[
i
];
int
v2Fragment
=
v2Fragments
[
i
];
if
(
v1Fragment
!=
v2Fragment
)
return
v1Fragment
.
compareTo
(
v2Fragment
);
i
++;
}
return
v1Fragments
.
length
.
compareTo
(
v2Fragments
.
length
);
}
/// Matches on device type given an identifier.
///
/// Example device type identifiers:
/// ✓ com.apple.CoreSimulator.SimDeviceType.iPhone-5
/// ✓ com.apple.CoreSimulator.SimDeviceType.iPhone-6
/// ✓ com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus
/// ✗ com.apple.CoreSimulator.SimDeviceType.iPad-2
/// ✗ com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm
final
RegExp
_iosDeviceTypePattern
=
new
RegExp
(
r'com.apple.CoreSimulator.SimDeviceType.iPhone-(\d+)(.*)'
);
int
compareIphoneVersions
(
String
id1
,
String
id2
)
{
Match
m1
=
_iosDeviceTypePattern
.
firstMatch
(
id1
);
Match
m2
=
_iosDeviceTypePattern
.
firstMatch
(
id2
);
int
v1
=
int
.
parse
(
m1
[
1
]);
int
v2
=
int
.
parse
(
m2
[
1
]);
if
(
v1
!=
v2
)
return
v1
.
compareTo
(
v2
);
// Sorted in the least preferred first order.
const
qualifiers
=
const
<
String
>[
'-Plus'
,
''
,
's-Plus'
,
's'
];
int
q1
=
qualifiers
.
indexOf
(
m1
[
2
]);
int
q2
=
qualifiers
.
indexOf
(
m2
[
2
]);
return
q1
.
compareTo
(
q2
);
}
packages/flutter_tools/test/src/ios/simulators_test.dart
0 → 100644
View file @
9383466d
import
'package:test/test.dart'
;
import
'package:flutter_tools/src/ios/simulators.dart'
;
main
()
{
group
(
'compareIosVersions'
,
()
{
test
(
'compares correctly'
,
()
{
// This list must be sorted in ascending preference order
List
<
String
>
testList
=
<
String
>[
'8'
,
'8.0'
,
'8.1'
,
'8.2'
,
'9'
,
'9.0'
,
'9.1'
,
'9.2'
,
'10'
,
'10.0'
,
'10.1'
,
];
for
(
int
i
=
0
;
i
<
testList
.
length
;
i
++)
{
expect
(
compareIosVersions
(
testList
[
i
],
testList
[
i
]),
0
);
}
for
(
int
i
=
0
;
i
<
testList
.
length
-
1
;
i
++)
{
for
(
int
j
=
i
+
1
;
j
<
testList
.
length
;
j
++)
{
expect
(
compareIosVersions
(
testList
[
i
],
testList
[
j
]),
lessThan
(
0
));
expect
(
compareIosVersions
(
testList
[
j
],
testList
[
i
]),
greaterThan
(
0
));
}
}
});
});
group
(
'compareIphoneVersions'
,
()
{
test
(
'compares correctly'
,
()
{
// This list must be sorted in ascending preference order
List
<
String
>
testList
=
<
String
>[
'com.apple.CoreSimulator.SimDeviceType.iPhone-4s'
,
'com.apple.CoreSimulator.SimDeviceType.iPhone-5'
,
'com.apple.CoreSimulator.SimDeviceType.iPhone-5s'
,
'com.apple.CoreSimulator.SimDeviceType.iPhone-6strange'
,
'com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus'
,
'com.apple.CoreSimulator.SimDeviceType.iPhone-6'
,
'com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus'
,
'com.apple.CoreSimulator.SimDeviceType.iPhone-6s'
,
];
for
(
int
i
=
0
;
i
<
testList
.
length
;
i
++)
{
expect
(
compareIphoneVersions
(
testList
[
i
],
testList
[
i
]),
0
);
}
for
(
int
i
=
0
;
i
<
testList
.
length
-
1
;
i
++)
{
for
(
int
j
=
i
+
1
;
j
<
testList
.
length
;
j
++)
{
expect
(
compareIphoneVersions
(
testList
[
i
],
testList
[
j
]),
lessThan
(
0
));
expect
(
compareIphoneVersions
(
testList
[
j
],
testList
[
i
]),
greaterThan
(
0
));
}
}
});
});
}
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