@@ -9,11 +9,25 @@ class Xcrun {
99 /// A return value of `true` doesn't mean the app is visible. The app might
1010 /// be in the background, but still in memory.
1111 static Future <bool > isAppRunning (String appBundleId) async {
12- final result = await Process .run (
13- "sh" ,
14- ["-c" , "xcrun simctl spawn booted launchctl list | grep \" $appBundleId \" " ],
15- );
12+ // final result = await Process.run(
13+ // "sh",
14+ // [
15+ // "-c",
16+ // "xcrun simctl spawn booted launchctl list | grep \"$appBundleId\"",
17+ // ],
18+ // runInShell: true,
19+ // );
20+
21+ // final result = await Process.run("sh", [
22+ // "-c",
23+ // "xcrun simctl spawn booted launchctl list | grep \"$appBundleId\"",
24+ // ]);
25+
26+ final result = await _runInShell ([
27+ "xcrun simctl spawn booted launchctl list | grep \" $appBundleId \" " ,
28+ ]);
1629 final output = result.stdout;
30+ print ("Is app running? ${output != null && output is String && output .isNotEmpty }" );
1731 return output != null && output is String && output.isNotEmpty;
1832 }
1933
@@ -28,18 +42,24 @@ class Xcrun {
2842 void Function (String )? onLog,
2943 void Function (String )? onError,
3044 }) async {
31- final result = await Process .start ("xcrun" , [
32- "simctl" ,
33- "spawn" ,
34- "booted" ,
35- "log" ,
36- "stream" ,
37- "--level" ,
38- "debug" ,
39- // Only log things related to the desired app.
40- "--predicate" ,
41- "(eventMessage CONTAINS '$appBundleId ' OR eventMessage CONTAINS 'flutter')" ,
42- ]);
45+ // This command doesn't work when run with a "sh -c". It also doesn't
46+ // work when concatenating the args into a single string.
47+ final result = await Process .start (
48+ "xcrun" ,
49+ [
50+ "simctl" ,
51+ "spawn" ,
52+ "booted" ,
53+ "log" ,
54+ "stream" ,
55+ "--level" ,
56+ "debug" ,
57+ // Only log things related to the desired app.
58+ "--predicate" ,
59+ "(eventMessage CONTAINS '$appBundleId ' OR eventMessage CONTAINS 'flutter')" ,
60+ ],
61+ runInShell: true ,
62+ );
4363
4464 result.stdout.transform (utf8.decoder).listen (onLog);
4565 result.stderr.transform (utf8.decoder).listen (onError);
@@ -52,8 +72,8 @@ class Xcrun {
5272 ///
5373 /// This is useful, for example, when you want to connect to the Dart VM service
5474 /// running in a debug Flutter app on an iOS device.
55- static Future <void > forwardTcpPort (int port) async {
56- await Process . run ( "xcrun" , [ "simctl" , "port" , "forward" , "booted" , "$port :$port " ]);
75+ static Future <void > forwardTcpPort (int port) {
76+ return _runInShell ([ "xcrun" , "simctl" , "port" , "forward" , "booted" , "$port :$port " ]);
5777 }
5878
5979 /// Tells iOS to launch the given Universal Link, which might launch an app, if
@@ -62,13 +82,16 @@ class Xcrun {
6282 /// The structure of the deep link is determined by the given app.
6383 static Future <void > launchAppWithUniversalLink ({
6484 required String universalLink,
65- }) async {
66- // Not sure why we need to dispatch through a shell, but if we try to
67- // run the xcrun command directly, the deep link doesn't launch.
68- await Process .run ("sh" , [
69- "-c" ,
70- "xcrun simctl openurl booted \" $universalLink \" " ,
71- ]);
85+ }) {
86+ // Note: This command only works when run with "sh" and the
87+ // command as a single string. If the command is passed as
88+ // individual arguments, it doesn't work. If the command is
89+ // run without "sh" and `runInShell` is `true`, it won't work.
90+ return _runInShell (["xcrun simctl openurl booted \" $universalLink \" " ]);
91+ // return Process.run(
92+ // "sh",
93+ // ["-c", "xcrun simctl openurl booted \"$universalLink\""],
94+ // );
7295 }
7396
7497 /// Waits for the app with the given [appBundleId] to appear in memory.
@@ -98,11 +121,37 @@ class Xcrun {
98121
99122 /// Kills the app with the given [appBundleId] ID, e.g., `com.acme.myapp` .
100123 static Future <void > killApp (String appBundleId) async {
101- await Process .run ("xcrun" , ["simctl" , "terminate" , "booted" , appBundleId]);
124+ // final result = await _runInShell(["xcrun", "simctl", "terminate", "booted", appBundleId]);
125+ final result = await Process .run (
126+ "xcrun" ,
127+ ["simctl" , "terminate" , "booted" , appBundleId],
128+ runInShell: true ,
129+ );
130+ print ("Killed app - exit code: ${result .exitCode }" );
102131 }
103132
104133 /// Clears all logs in the iOS log stream.
105134 static Future <void > clearLogcat () async {
106- await Process .run ("xcrun" , ["simctl" , "spawn" , "booted" , "log" , "erase" ]);
135+ await _runInShell (["xcrun" , "simctl" , "spawn" , "booted" , "log" , "erase" ]);
136+ }
137+
138+ static Future <Process > _startInShell (List <String > commandAndArgs) {
139+ return Process .start ("sh" , ["-c" , ...commandAndArgs]);
140+
141+ // return Process.start(
142+ // commandAndArgs.first,
143+ // commandAndArgs.length > 1 ? commandAndArgs.sublist(1) : [],
144+ // runInShell: true,
145+ // );
146+ }
147+
148+ static Future <ProcessResult > _runInShell (List <String > commandAndArgs) {
149+ print ("Sending shell command: '${commandAndArgs .join (" " )}'" );
150+ return Process .run ("sh" , ["-c" , ...commandAndArgs]);
151+ // return Process.run(
152+ // commandAndArgs.first,
153+ // commandAndArgs.length > 1 ? commandAndArgs.sublist(1) : [],
154+ // runInShell: true,
155+ // );
107156 }
108157}
0 commit comments