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
d38b9a02
Commit
d38b9a02
authored
Feb 06, 2016
by
Devon Carew
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1634 from devoncarew/watch_sim_devices
Watch sim devices
parents
8999886f
67124dc3
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
269 additions
and
157 deletions
+269
-157
daemon.dart
packages/flutter_tools/lib/src/commands/daemon.dart
+66
-2
install.dart
packages/flutter_tools/lib/src/commands/install.dart
+7
-5
device_ios.dart
packages/flutter_tools/lib/src/ios/device_ios.dart
+23
-150
simulator.dart
packages/flutter_tools/lib/src/ios/simulator.dart
+173
-0
No files found.
packages/flutter_tools/lib/src/commands/daemon.dart
View file @
d38b9a02
...
...
@@ -10,6 +10,8 @@ import '../android/adb.dart';
import
'../android/device_android.dart'
;
import
'../base/context.dart'
;
import
'../device.dart'
;
import
'../ios/device_ios.dart'
;
import
'../ios/simulator.dart'
;
import
'../runner/flutter_command.dart'
;
import
'start.dart'
;
import
'stop.dart'
as
stop
;
...
...
@@ -291,18 +293,32 @@ class DeviceDomain extends Domain {
_androidDeviceDiscovery
.
onChanged
.
listen
((
Device
device
)
{
sendEvent
(
'device.changed'
,
_deviceToMap
(
device
));
});
if
(
Platform
.
isMacOS
)
{
_iosSimulatorDeviceDiscovery
=
new
IOSSimulatorDeviceDiscovery
();
_iosSimulatorDeviceDiscovery
.
onAdded
.
listen
((
Device
device
)
{
sendEvent
(
'device.added'
,
_deviceToMap
(
device
));
});
_iosSimulatorDeviceDiscovery
.
onRemoved
.
listen
((
Device
device
)
{
sendEvent
(
'device.removed'
,
_deviceToMap
(
device
));
});
}
}
AndroidDeviceDiscovery
_androidDeviceDiscovery
;
IOSSimulatorDeviceDiscovery
_iosSimulatorDeviceDiscovery
;
Future
<
List
<
Device
>>
getDevices
(
dynamic
args
)
{
List
<
Device
>
devices
=
<
Device
>[];
devices
.
addAll
(
_androidDeviceDiscovery
.
getDevices
());
if
(
_iosSimulatorDeviceDiscovery
!=
null
)
devices
.
addAll
(
_iosSimulatorDeviceDiscovery
.
getDevices
());
return
new
Future
.
value
(
devices
);
}
void
dispose
()
{
_androidDeviceDiscovery
.
dispose
();
_iosSimulatorDeviceDiscovery
?.
dispose
();
}
}
...
...
@@ -311,7 +327,7 @@ class AndroidDeviceDiscovery {
_initAdb
();
if
(
_adb
!=
null
)
{
_subscription
=
_adb
.
trackDevices
().
listen
(
_handle
New
Devices
);
_subscription
=
_adb
.
trackDevices
().
listen
(
_handle
Updated
Devices
);
}
}
...
...
@@ -337,7 +353,7 @@ class AndroidDeviceDiscovery {
}
}
void
_handle
New
Devices
(
List
<
AdbDevice
>
newDevices
)
{
void
_handle
Updated
Devices
(
List
<
AdbDevice
>
newDevices
)
{
List
<
AndroidDevice
>
currentDevices
=
new
List
.
from
(
getDevices
());
for
(
AdbDevice
device
in
newDevices
)
{
...
...
@@ -383,6 +399,54 @@ class AndroidDeviceDiscovery {
}
}
class
IOSSimulatorDeviceDiscovery
{
IOSSimulatorDeviceDiscovery
()
{
_subscription
=
SimControl
.
trackDevices
().
listen
(
_handleUpdatedDevices
);
}
StreamSubscription
<
List
<
SimDevice
>>
_subscription
;
Map
<
String
,
IOSSimulator
>
_devices
=
new
Map
<
String
,
IOSSimulator
>();
StreamController
<
Device
>
addedController
=
new
StreamController
<
Device
>.
broadcast
();
StreamController
<
Device
>
removedController
=
new
StreamController
<
Device
>.
broadcast
();
List
<
Device
>
getDevices
()
=>
_devices
.
values
.
toList
();
Stream
<
Device
>
get
onAdded
=>
addedController
.
stream
;
Stream
<
Device
>
get
onRemoved
=>
removedController
.
stream
;
void
_handleUpdatedDevices
(
List
<
SimDevice
>
newDevices
)
{
List
<
IOSSimulator
>
currentDevices
=
new
List
.
from
(
getDevices
());
for
(
SimDevice
device
in
newDevices
)
{
IOSSimulator
androidDevice
=
_devices
[
device
.
udid
];
if
(
androidDevice
==
null
)
{
// device added
androidDevice
=
new
IOSSimulator
(
id:
device
.
udid
,
name:
device
.
name
);
_devices
[
androidDevice
.
id
]
=
androidDevice
;
addedController
.
add
(
androidDevice
);
}
else
{
currentDevices
.
remove
(
androidDevice
);
}
}
// device removed
for
(
IOSSimulator
device
in
currentDevices
)
{
_devices
.
remove
(
device
.
id
);
Device
.
removeFromCache
(
device
.
id
);
removedController
.
add
(
device
);
}
}
void
dispose
()
{
_subscription
?.
cancel
();
}
}
Map
<
String
,
dynamic
>
_deviceToMap
(
Device
device
)
{
return
<
String
,
dynamic
>{
'id'
:
device
.
id
,
...
...
packages/flutter_tools/lib/src/commands/install.dart
View file @
d38b9a02
...
...
@@ -3,9 +3,11 @@
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:io'
;
import
'../application_package.dart'
;
import
'../device.dart'
;
import
'../ios/simulator.dart'
;
import
'../runner/flutter_command.dart'
;
class
InstallCommand
extends
FlutterCommand
{
...
...
@@ -19,7 +21,7 @@ class InstallCommand extends FlutterCommand {
@override
Future
<
int
>
runInProject
()
async
{
await
downloadApplicationPackagesAndConnectToDevices
();
bool
installedAny
=
installApp
(
bool
installedAny
=
await
installApp
(
devices
,
applicationPackages
,
boot:
argResults
[
'boot'
]
...
...
@@ -28,13 +30,13 @@ class InstallCommand extends FlutterCommand {
}
}
bool
installApp
(
Future
<
bool
>
installApp
(
DeviceStore
devices
,
ApplicationPackageStore
applicationPackages
,
{
bool
boot:
false
})
{
if
(
boot
)
devices
.
iOSSimulator
?
.
boot
();
})
async
{
if
(
boot
&&
Platform
.
isMacOS
)
await
SimControl
.
boot
();
bool
installedSomewhere
=
false
;
...
...
packages/flutter_tools/lib/src/ios/device_ios.dart
View file @
d38b9a02
...
...
@@ -14,6 +14,11 @@ import '../base/process.dart';
import
'../build_configuration.dart'
;
import
'../device.dart'
;
import
'../toolchain.dart'
;
import
'simulator.dart'
;
const
String
_ideviceinstallerInstructions
=
'To work with iOS devices, please install ideviceinstaller.
\n
'
'If you use homebrew, you can install it with "
\$
brew install ideviceinstaller".'
;
class
IOSDeviceDiscovery
extends
DeviceDiscovery
{
List
<
Device
>
_devices
=
<
Device
>[];
...
...
@@ -44,11 +49,6 @@ class IOSSimulatorDiscovery extends DeviceDiscovery {
class
IOSDevice
extends
Device
{
static
final
String
defaultDeviceID
=
'default_ios_id'
;
static
const
String
_macInstructions
=
'To work with iOS devices, please install ideviceinstaller. '
'If you use homebrew, you can install it with '
'"
\$
brew install ideviceinstaller".'
;
String
_installerPath
;
String
get
installerPath
=>
_installerPath
;
...
...
@@ -123,7 +123,7 @@ class IOSDevice extends Device {
static
final
Map
<
String
,
String
>
_commandMap
=
{};
static
String
_checkForCommand
(
String
command
,
[
String
macInstructions
=
_
mac
Instructions
String
macInstructions
=
_
ideviceinstaller
Instructions
])
{
return
_commandMap
.
putIfAbsent
(
command
,
()
{
try
{
...
...
@@ -263,78 +263,27 @@ class IOSDevice extends Device {
}
class
IOSSimulator
extends
Device
{
static
final
String
defaultDeviceID
=
'default_ios_sim_id'
;
static
const
String
_macInstructions
=
'To work with iOS devices, please install ideviceinstaller. '
'If you use homebrew, you can install it with '
'"
\$
brew install ideviceinstaller".'
;
static
String
_xcrunPath
=
path
.
join
(
'/usr'
,
'bin'
,
'xcrun'
);
String
_iOSSimPath
;
String
get
iOSSimPath
=>
_iOSSimPath
;
String
get
xcrunPath
=>
_xcrunPath
;
String
_name
;
String
get
name
=>
_name
;
factory
IOSSimulator
({
String
id
,
String
name
,
String
iOSSimulatorPath
})
{
IOSSimulator
device
=
Device
.
unique
(
id
??
defaultDeviceID
,
(
String
id
)
=>
new
IOSSimulator
.
fromId
(
id
));
factory
IOSSimulator
({
String
id
,
String
name
})
{
IOSSimulator
device
=
Device
.
unique
(
id
,
(
String
id
)
=>
new
IOSSimulator
.
fromId
(
id
));
device
.
_name
=
name
;
if
(
iOSSimulatorPath
==
null
)
{
iOSSimulatorPath
=
path
.
join
(
'/Applications'
,
'iOS Simulator.app'
,
'Contents'
,
'MacOS'
,
'iOS Simulator'
);
}
device
.
_iOSSimPath
=
iOSSimulatorPath
;
return
device
;
}
static
List
<
IOSSimulator
>
getAttachedDevices
()
{
return
SimControl
.
getConnectedDevices
().
map
((
SimDevice
device
)
{
return
new
IOSSimulator
(
id:
device
.
udid
,
name:
device
.
name
);
}).
toList
();
}
IOSSimulator
.
fromId
(
String
id
)
:
super
.
fromId
(
id
);
static
_IOSSimulatorInfo
_getRunningSimulatorInfo
([
IOSSimulator
mockIOS
])
{
String
xcrunPath
=
mockIOS
!=
null
?
mockIOS
.
xcrunPath
:
_xcrunPath
;
String
output
=
runCheckedSync
([
xcrunPath
,
'simctl'
,
'list'
,
'devices'
]);
Match
match
;
// iPhone 6s Plus (8AC808E1-6BAE-4153-BBC5-77F83814D414) (Booted)
Iterable
<
Match
>
matches
=
new
RegExp
(
r'[\W]*(.*) \(([^\)]+)\) \(Booted\)'
,
multiLine:
true
).
allMatches
(
output
);
if
(
matches
.
length
>
1
)
{
// More than one simulator is listed as booted, which is not allowed but
// sometimes happens erroneously. Kill them all because we don't know
// which one is actually running.
printError
(
'Multiple running simulators were detected, '
'which is not supposed to happen.'
);
for
(
Match
match
in
matches
)
{
if
(
match
.
groupCount
>
0
)
{
// TODO(devoncarew): We're killing simulator devices inside an accessor
// method; we probably shouldn't be changing state here.
printError
(
'Killing simulator
${match.group(1)}
'
);
runSync
([
xcrunPath
,
'simctl'
,
'shutdown'
,
match
.
group
(
2
)]);
}
}
}
else
if
(
matches
.
length
==
1
)
{
match
=
matches
.
first
;
}
String
_name
;
String
get
name
=>
_name
;
if
(
match
!=
null
&&
match
.
groupCount
>
0
)
{
return
new
_IOSSimulatorInfo
(
match
.
group
(
2
),
match
.
group
(
1
));
}
else
{
printTrace
(
'No running simulators found'
);
return
null
;
}
}
String
get
xcrunPath
=>
path
.
join
(
'/usr'
,
'bin'
,
'xcrun'
);
String
_getSimulatorPath
()
{
String
deviceID
=
id
==
defaultDeviceID
?
_getRunningSimulatorInfo
()?.
id
:
id
;
if
(
deviceID
==
null
)
return
null
;
return
path
.
join
(
_homeDirectory
,
'Library'
,
'Developer'
,
'CoreSimulator'
,
'Devices'
,
deviceID
);
return
path
.
join
(
_homeDirectory
,
'Library'
,
'Developer'
,
'CoreSimulator'
,
'Devices'
,
id
);
}
String
_getSimulatorAppHomeDirectory
(
ApplicationPackage
app
)
{
...
...
@@ -344,59 +293,13 @@ class IOSSimulator extends Device {
return
path
.
join
(
simulatorPath
,
'data'
);
}
static
List
<
IOSSimulator
>
getAttachedDevices
([
IOSSimulator
mockIOS
])
{
List
<
IOSSimulator
>
devices
=
[];
try
{
_IOSSimulatorInfo
deviceInfo
=
_getRunningSimulatorInfo
(
mockIOS
);
if
(
deviceInfo
!=
null
)
devices
.
add
(
new
IOSSimulator
(
id:
deviceInfo
.
id
,
name:
deviceInfo
.
name
));
}
catch
(
e
)
{
}
return
devices
;
}
Future
<
bool
>
boot
()
async
{
if
(!
Platform
.
isMacOS
)
return
false
;
if
(
isConnected
())
return
true
;
if
(
id
==
defaultDeviceID
)
{
runDetached
([
iOSSimPath
]);
Future
<
bool
>
checkConnection
([
int
attempts
=
20
])
async
{
if
(
attempts
==
0
)
{
printStatus
(
'Timed out waiting for iOS Simulator
$id
to boot.'
);
return
false
;
}
if
(!
isConnected
())
{
printStatus
(
'Waiting for iOS Simulator
$id
to boot...'
);
return
await
new
Future
.
delayed
(
new
Duration
(
milliseconds:
500
),
()
=>
checkConnection
(
attempts
-
1
));
}
return
true
;
}
return
await
checkConnection
();
}
else
{
try
{
runCheckedSync
([
xcrunPath
,
'simctl'
,
'boot'
,
id
]);
}
catch
(
e
)
{
printError
(
'Unable to boot iOS Simulator
$id
: '
,
e
);
return
false
;
}
}
return
false
;
}
@override
bool
installApp
(
ApplicationPackage
app
)
{
if
(!
isConnected
())
return
false
;
try
{
if
(
id
==
defaultDeviceID
)
{
runCheckedSync
([
xcrunPath
,
'simctl'
,
'install'
,
'booted'
,
app
.
localPath
]);
}
else
{
runCheckedSync
([
xcrunPath
,
'simctl'
,
'install'
,
id
,
app
.
localPath
]);
}
SimControl
.
install
(
id
,
app
.
localPath
);
return
true
;
}
catch
(
e
)
{
return
false
;
...
...
@@ -407,14 +310,7 @@ class IOSSimulator extends Device {
bool
isConnected
()
{
if
(!
Platform
.
isMacOS
)
return
false
;
_IOSSimulatorInfo
deviceInfo
=
_getRunningSimulatorInfo
();
if
(
deviceInfo
==
null
)
{
return
false
;
}
else
if
(
deviceInfo
.
id
==
defaultDeviceID
)
{
return
true
;
}
else
{
return
_getRunningSimulatorInfo
()?.
id
==
id
;
}
return
SimControl
.
getConnectedDevices
().
any
((
SimDevice
device
)
=>
device
.
udid
==
id
);
}
@override
...
...
@@ -462,29 +358,13 @@ class IOSSimulator extends Device {
}
// Step 3: Install the updated bundle to the simulator
int
installResult
=
await
runCommandAndStreamOutput
([
xcrunPath
,
'simctl'
,
'install'
,
id
==
defaultDeviceID
?
'booted'
:
id
,
path
.
absolute
(
bundle
.
path
)
]);
if
(
installResult
!=
0
)
{
printError
(
'Could not install the application bundle on the simulator'
);
return
false
;
}
SimControl
.
install
(
id
,
path
.
absolute
(
bundle
.
path
));
// Step 4: Launch the updated application in the simulator
runCheckedSync
([
xcrunPath
,
'simctl'
,
'launch'
,
id
==
defaultDeviceID
?
'booted'
:
id
,
app
.
id
]);
SimControl
.
launch
(
id
,
app
.
id
);
printTrace
(
'Successfully started
${app.name}
on
$id
'
);
return
true
;
}
...
...
@@ -623,13 +503,6 @@ class _IOSSimulatorLogReader extends DeviceLogReader {
}
}
class
_IOSSimulatorInfo
{
final
String
id
;
final
String
name
;
_IOSSimulatorInfo
(
this
.
id
,
this
.
name
);
}
final
RegExp
_xcodeVersionRegExp
=
new
RegExp
(
r'Xcode (\d+)\..*'
);
final
String
_xcodeRequirement
=
'Xcode 7.0 or greater is required to develop for iOS.'
;
...
...
packages/flutter_tools/lib/src/ios/simulator.dart
0 → 100644
View file @
d38b9a02
// Copyright 2016 The Chromium 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:async'
;
import
'dart:convert'
show
JSON
;
import
'dart:io'
;
import
'../base/context.dart'
;
import
'../base/process.dart'
;
const
String
_xcrunPath
=
'/usr/bin/xcrun'
;
const
String
_simulatorPath
=
'/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app/Contents/MacOS/Simulator'
;
/// A wrapper around the `simctl` command line tool.
class
SimControl
{
static
Future
<
bool
>
boot
({
String
deviceId
})
async
{
if
(
_isAnyConnected
())
return
true
;
if
(
deviceId
==
null
)
{
runDetached
([
_simulatorPath
]);
Future
<
bool
>
checkConnection
([
int
attempts
=
20
])
async
{
if
(
attempts
==
0
)
{
printStatus
(
'Timed out waiting for iOS Simulator to boot.'
);
return
false
;
}
if
(!
_isAnyConnected
())
{
printStatus
(
'Waiting for iOS Simulator to boot...'
);
return
await
new
Future
.
delayed
(
new
Duration
(
milliseconds:
500
),
()
=>
checkConnection
(
attempts
-
1
)
);
}
return
true
;
}
return
await
checkConnection
();
}
else
{
try
{
runCheckedSync
([
_xcrunPath
,
'simctl'
,
'boot'
,
deviceId
]);
return
true
;
}
catch
(
e
)
{
printError
(
'Unable to boot iOS Simulator
$deviceId
: '
,
e
);
return
false
;
}
}
return
false
;
}
/// Returns a list of all available devices, both potential and connected.
static
List
<
SimDevice
>
getDevices
()
{
// {
// "devices" : {
// "com.apple.CoreSimulator.SimRuntime.iOS-8-2" : [
// {
// "state" : "Shutdown",
// "availability" : " (unavailable, runtime profile not found)",
// "name" : "iPhone 4s",
// "udid" : "1913014C-6DCB-485D-AC6B-7CD76D322F5B"
// },
// ...
List
<
String
>
args
=
<
String
>[
'simctl'
,
'list'
,
'--json'
,
'devices'
];
printTrace
(
'
$_xcrunPath
${args.join(' ')}
'
);
ProcessResult
results
=
Process
.
runSync
(
_xcrunPath
,
args
);
if
(
results
.
exitCode
!=
0
)
{
printError
(
'Error executing simctl:
${results.exitCode}
\n
${results.stderr}
'
);
return
<
SimDevice
>[];
}
List
<
SimDevice
>
devices
=
<
SimDevice
>[];
Map
<
String
,
Map
<
String
,
dynamic
>>
data
=
JSON
.
decode
(
results
.
stdout
);
Map
<
String
,
dynamic
>
devicesSection
=
data
[
'devices'
];
for
(
String
deviceCategory
in
devicesSection
.
keys
)
{
List
<
dynamic
>
devicesData
=
devicesSection
[
deviceCategory
];
for
(
Map
<
String
,
String
>
data
in
devicesData
)
{
devices
.
add
(
new
SimDevice
(
deviceCategory
,
data
));
}
}
return
devices
;
}
/// Returns all the connected simulator devices.
static
List
<
SimDevice
>
getConnectedDevices
()
{
return
getDevices
().
where
((
SimDevice
device
)
=>
device
.
isBooted
).
toList
();
}
static
StreamController
<
List
<
SimDevice
>>
_trackDevicesControler
;
/// Listens to changes in the set of connected devices. The implementation
/// currently uses polling. Callers should be careful to call cancel() on any
/// stream subscription when finished.
///
/// TODO(devoncarew): We could investigate using the usbmuxd protocol directly.
static
Stream
<
List
<
SimDevice
>>
trackDevices
()
{
if
(
_trackDevicesControler
==
null
)
{
Timer
timer
;
Set
<
String
>
deviceIds
=
new
Set
<
String
>();
_trackDevicesControler
=
new
StreamController
.
broadcast
(
onListen:
()
{
timer
=
new
Timer
.
periodic
(
new
Duration
(
seconds:
4
),
(
Timer
timer
)
{
List
<
SimDevice
>
devices
=
getConnectedDevices
();
if
(
_updateDeviceIds
(
devices
,
deviceIds
))
{
_trackDevicesControler
.
add
(
devices
);
}
});
},
onCancel:
()
{
timer
?.
cancel
();
deviceIds
.
clear
();
}
);
}
return
_trackDevicesControler
.
stream
;
}
/// Update the cached set of device IDs and return whether there were any changes.
static
bool
_updateDeviceIds
(
List
<
SimDevice
>
devices
,
Set
<
String
>
deviceIds
)
{
Set
<
String
>
newIds
=
new
Set
<
String
>.
from
(
devices
.
map
((
SimDevice
device
)
=>
device
.
udid
));
bool
changed
=
false
;
for
(
String
id
in
newIds
)
{
if
(!
deviceIds
.
contains
(
id
))
changed
=
true
;
}
for
(
String
id
in
deviceIds
)
{
if
(!
newIds
.
contains
(
id
))
changed
=
true
;
}
deviceIds
.
clear
();
deviceIds
.
addAll
(
newIds
);
return
changed
;
}
static
bool
_isAnyConnected
()
=>
getConnectedDevices
().
isNotEmpty
;
static
void
install
(
String
deviceId
,
String
appPath
)
{
runCheckedSync
([
_xcrunPath
,
'simctl'
,
'install'
,
deviceId
,
appPath
]);
}
static
void
launch
(
String
deviceId
,
String
appIdentifier
,
[
List
<
String
>
launchArgs
])
{
List
<
String
>
args
=
[
_xcrunPath
,
'simctl'
,
'launch'
,
deviceId
,
appIdentifier
];
if
(
launchArgs
!=
null
)
args
.
addAll
(
launchArgs
);
runCheckedSync
(
args
);
}
}
class
SimDevice
{
SimDevice
(
this
.
category
,
this
.
data
);
final
String
category
;
final
Map
<
String
,
String
>
data
;
String
get
state
=>
data
[
'state'
];
String
get
availability
=>
data
[
'availability'
];
String
get
name
=>
data
[
'name'
];
String
get
udid
=>
data
[
'udid'
];
bool
get
isBooted
=>
state
==
'Booted'
;
}
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