How to run a system event AppleScript from a hardened macOS app? - swift

I've developed SOL, an open-source macOS launcher.
Inside of SOL, I added the ability to run AppleScript commands, one of these commands allows me to lock the computer:
{
iconImage: Assets.LockIcon,
name: 'Lock',
type: ItemType.CONFIGURATION,
callback: () => {
solNative.executeAppleScript(
`tell application "System Events" to keystroke "q" using {control down, command down}`,
)
},
},
I have also added the correct entitlements for the hardened runtime (it is distributed only via DeveloperID and not via app store, so hardened runtime is the only capability needed)
<key>com.apple.security.temporary-exception.apple-events</key>
<array>
<string>com.apple.systemevents</string>
<string>com.apple.systempreferences</string>
</array>
The problem is: when I run the app via XCode it works fine, but once the app is packaged and distributed via DeveloperID signed binary, then the lock AppleScript stops working.
Looking at System Preferences I can see the app is still registered and has automation access:
Why does the script stop working? If I remove the permission and re-add it then it starts working again. Does it have to do with the binary? Or is there some permission model I am missing? I had a similar problem with folder access with a different app, so could it be something similar (a security feature I'm not aware of?)
EDIT 1:
Looking through the console.app logs there is also no error message.
EDIT 2:
I just managed to reproduce the issue while attached to XCode and log the output of calling the AppleScript:
Optional({
NSAppleScriptErrorAppName = "System Events";
NSAppleScriptErrorBriefMessage = "Sol is not allowed to send keystrokes.";
NSAppleScriptErrorMessage = "System Events got an error: Sol is not allowed to send keystrokes.";
NSAppleScriptErrorNumber = 1002;
NSAppleScriptErrorRange = "NSRange: {36, 48}";
})
But the app does have accessibility permissions but this still happens? 🥴
EDIT 3:
I just tried removing the app from the accessibility panel and re-adding it, and now the script works again. I killed the app and started it again, and it still works. So my guess right now, is that it has something to do with the binary. Maybe if I replace it with a new version then the accessibility setting doesn't work anymore?

After much gathering at hints all over the internet, I've come to the conclusion that the problem lies in having different binaries.
It makes sense that macOS does some binary check to make sure the application has not been swaped. I had therefore two binaries in my machine a "release" one, which was DeveloperID signed. And the XCode debug one, which uses a development certificate. So both are different and therefore do not pass the binary check.
The brute force solution is not to have a release version installed in my machine. Another solution would be to have the debug binary have a different bundle ID (com.ospfranco.sol), so that macOS allows both the release binary and the debug binary to have accessibility access.

Related

CGPreflightScreenCaptureAccess always returns false in development builds

I'm writing an app for macOS (12.1 locally) in Xcode 13.2.1. I need screenshot access, and it seems like the easiest way to get permission for that (in macOS 11 and later) is to use CGRequestScreenCaptureAccess, and to check eligibility using CGPreflightScreenCaptureAccess:
https://stackoverflow.com/a/65423834/444912
My code essentially looks like this:
let hasScreenAccess = CGPreflightScreenCaptureAccess();
if (!hasScreenAccess) {
CGRequestScreenCaptureAccess()
}
When I run a fresh build, a modal appears as expected:
and I'm able to see my app appear in System Preferences, also as expected:
Enabling my app's permissions prompts me to quit my app and restart it. This restarts my production copy of my app, from the app store. However, if I quit that and re-run the same build in XCode, my build is still not granted permission to record the screen (even though it appears as enabled in System Preferences). How do I allow my app to have permissions to record my screen locally?
We had a similar issue after renaming one of our apps which made use of the /usr/sbin/screencapture command line tool. The security prompt appeared every time a screen capture was triggered, no matter the activation status in System Preferences.
During development, the tccutil reset ScreenCapture {bundle identifier} command helped keep the permissions clean for subsequent testing.
I solved this in the process of writing this question, so I figured I'd share my answer. If I delete the copy of my app from my Applications folder, things seem to work. I assume that there is some sort of "claiming" process that goes.
It seems to work if I rename the copy of the app in my Applications folder, delete the screen recording in System Preferences, and then run my fresh build from Xcode.
In System Preferences, it can be the production copy of your app. You may need to replace it with your debug build app.
Delete it from System Preferences.
Locate your debug build app in Finder and drag & drop it to System Preferences.
Your debug build app must be given the permission.

XCode multiple errors (No such command "-no_deduplicate")

I've build an app which is using firebase auth, database, storage and core.
But when I build my app, there are coming multiple errors, one of them is
"No such command: '-no_deduplicate'".
And file-not-found errors that are searching any simulator architecture file containing the path /i386/, but I haven't memorized them.
Thank you for your help,
MarvMan
IIRC it's a warning and if you run your app in build mode instead of dev mode this specific warning goes away

Xcode 4.2. gets stuck "Attaching to myapp" when running

In xcode 4.2, sometimes when you're going to run your ios proj on simulator, the status windows says "Attaching to myapp", and just gets stuck there... until you cancel.
Now, this has been asked before:
XCode 4 hangs at "Attaching to (app name)"
and surprisingly, besides the accepted answer on that thread, there are at least 10 other possible solutions others have been adding, all for the same issue, people says one of them worked while the others didn't...
please note, this is not a sequence of steps. each one is a possible solution:
1- restart xcode and/or restart simulator (reset content and settings) and/or restart computer.
2- click on project name in project navigator. in build settings tab, go to packaging and make sure that "Product Name" is the same that the one xcode says simulator is attaching to when running. if they are different, it will fail.
3- go to your projectname.xcodeproj folder. inside there delete anything named with your userid. when you reopen xcode those files will be recreated and it should work…
4- Manually delete the build directory for your project.
5- Go to organizer window. select Projects, select your app in the left hand side and then delete over "Derived Data"
6- Check Launch option is set to "Automatically" in Product->Edit Scheme, "Run" scheme.
7- In Project->"Edit Schemes"->Run. Change the Debugger from GDB to None (this doesn't make sense to me..).
8- Kill the process gdb-i386-apple-darwin from Activity Monitor. this is assuming gdb is not responding.
9- In "Product"->Edit Scheme. in Run, click yourappname.app, choose other, navigate to your .app in your project. now run.
10- Check that you don't have two different Info.plist in your project. if you do, remove the bad one.
In my case, none of them do the job. My project builds succesfully, everything seems fine, .plist, bundle identifier, name, etc.. and still can't pass the "attaching" part. i don't understand the reason of this, so any suggestions to fix it and possibly understand the problem i'll really appreciate it.
New projects were failing to launch in the simulator, getting stuck on the attach step.
This seems to be after Xcode 4.3 was installed, but I can't recall the last new project I created.
This is what worked for me, the clue coming from this thread...
Project->"Edit Schemes"->Run. Change the Debugger from LLDB to GDB
Another computer with the same version of Xcode works fine. Maybe my LLDB is corrupt?
Did you recently upgrade to OSX 10.7.2? I started having the same problem after I upgraded. I noticed that the Simulator always get stuck if I'm connected to a Wi-Fi network that forces Captive Portal authentication. This happens with other apps as well (Chrome, Safari). I'm not really sure why this happens, but I did read that 10.7.2 has issues with Captive Portal authentication.
Anyway, in my case, I repaired disk permission from Disk Utility and rebooted my machine. This seems to resolve the issue.
Just rebooting the computer worked for me.
Tried all the solutions but none applied to my case. XCode 4.2, OS X 10.6.8
Found that the Info.plist bundle identifier had been accidentally deleted when adding a custom app icon. Adding that back fixed the problem.
Anyway that's my fix, hope it helps someone.
Also before figuring out that, found I could start the simulator from another app and then use the app icon on the simulator for the app that would not attach, and start it up that way.
seems like there seem to be a lot of things causing this, but one thing that worked for me was simply cleaning out the build folder by pressing Cmd+Option+Shift+K or alternately if you select the Product dropdown in the toolbar and hold the Option button you should see the "Clean Build Folder" option appear
I also tried all solutions in that topic but all failed. But finally it was found out that what was went wrong.
What made this issue occurred is that some settings in Target->Build Settings was got modified by me for including C headers. And after I added all C headers and make it built. This issue occurred.
It might be only works on the situation I described before.
I just created an empty project and check all items in Target->Build Settings between the attaching-stuck app and the empty one. It was found that some items in the attaching-stuck one was different from the empty one.
So I deleted it and make it attached successfully.
It seems different in my case and also solved in a different way. If you got stuck every time after drop some files or folders into your project with the 'Create folder references for any added folders' way, this will be the solution.
Click the project node(the root node) on Xcode's project navigator and select target node. It's under the 'TARGETS'. Then click the 'Build Phases' tab. There are 4 sections of some list and you can click the triangle to expand the list.
You need to concentrate on the 'Compile Sources' and 'Copy Bundle Resources' section. Code files like .m must be placed on the 'Compile Sources' section and are compiled automatically. Resource files like .jpg must be placed on the 'Copy Bundle Resources' section and are copied into the project's package.
So, if the dropped files and folders are not in the 'Copy Bundle Resources' list, just drag it form the project navigator and drop onto the list. That will solve the problem.
If it doesn't work, delete all the referenced files and folders, click '+' button on the resource (or compile) section and click 'Add other...' button. Then you can include files and folders as the 'Create folder references for any added folders' way. I think the 'drag and drop' works well after the '+ button' way is done once.
In addition, 'Resource' may not allowed for folder name.
I experienced the 'stuck' problem every time when I attach files and folders as reference on Xcode 4.2 ~ 4.3.3. Reinstalling mac was a useless effort for me.
I have noted in Lion that when the iOS sim locks up or hangs the app,
that if I go to a shell, and do ps -ef |grep SDK, I will
see many, many processes running associated with the simulator.
I tried to kill off these processes but they rapidly respawn
and the only solution then is to reboot. Also, in the ps output,
you will also see instances of your app running as well.
So the Simulator issue is caused by previously running processes
that appear to block the correct running of the latest one.
I guess Apple will have a fix for this eventually, as it is quite onerous.
Rebooting works for me, too, but this shouldn't be necessary. I'd recommend filing a bug at bugreport.apple.com. You can duplicate the one I created - the more it's duplicated, the more likely Apple is to fix the problem.
I tried all of the solutions above but without luck ...
When I search for simular problem here :
Xcode error: failed to launch [directory] -- invalid host string: 'localhost'
I found it fixed my problem!
Hope this helps those who are still searching for a clue .
Upgrading to XCode 4.6.2 resolved this issue for me
Even if the app is not attaching after cleaning the project, changing the app name, restart the by resetting the simulator, and if you are using LLDB compiler, it is because the LLDB compiler is not able to connect to the local debug server in order to solve this, take a look at this
Why does the LLDB Debugger constantly fail to attach?
This really solves your problem!

Receive message "A signed resource has been added, modified, or deleted" when trying to debug an App on iPhone

While attempting to debug a build created using the 3.2 SDK on an iPhone device I receive the message "A signed resource has been added, modified, or deleted.".
I can clean, rebuild, then install with no error, but if I try to install without cleaning the error shows.
Anyone have an idea as to what might be causing this?
I found a workaround for the bug.
If you delete the .app file in build/Debug-iphoneos/ before building for the device, the app gets installed without errors.
And there is a simple way to do that before every build.
Make sure you have selected "Device" in the dropdown overview menu.
In XCode go to Project > New target...
Then find "Shell Script target" under MacOSX/Other
Name it and add it to the current project
Now, in the left navigation panel, under targets, expand your newly created target and double-click on Run Script.
In the window that opens replace "# shell script goes here" with "rm -fr build/Debug-iphoneos/*.app" (without the quotes).
Now open your main target preferences and under Direct Dependencies add your newly created target.
Build and Go! :)
This error occurs when there is a special character in the Product Name. In my case it was a "?"
If you change the Product Name it automatically updates the "Bundle Name" and "Bundle Display Name" so it is often the best choice to rename an app.
If you want to include special characters in the app name you have to manually rename the "Bundle Name" and "Bundle Display Name"
Bundle Name: This is the actual app bundle name in the file system such as "Awesome App.app". It is generally not visible to the user.
Bundle Display Name: This is a short name displayed under the app icon on the device. Since the bundle name would be truncated to "Awes…tion" you have the option to have a shorter name which fits better such as "Awesome App". It should be similar to the App Store name (set in iTunes Connect)
This is pretty clearly a bug in the 3.2 SDK, but I don't want to downgrade. I've found that doing a Clean by pushing Command+Shift+K, then Return is pretty fast before pushing Command+R to build.
Xcode 8, reason of the "A signed resource has been added, modified, or deleted." was that target was signed with an enterprise provision profile.
In my case, it happened when no changes were made. Make a change to any file and run again.
This can have several causes. The fastest way to figure out what is causing it is to go into Xcode, Window menu, Devices, then click the reveal button at the bottom of the pane to show the Console. Now attempt to run. You should see log output that names the specific files it is complaining about.
Most of the solutions previously posted are just artificial ways of getting Xcode to regenerate the contents of the build folder and/or re-sign the files.
In my case, my WatchKit extension was somehow acquiring references to Cocoapods frameworks that were only targeted toward the main app so they got signed during the build, then pruned later (as they were not used). Then on device, iOS complained that they were missing from the .appex folder for the extension. I ended up not needing any pods in the extension so I just removed them all and removed the extension as a target, then did some minor cleanup to remove the pod-related debris left in the build steps. Now everything works perfectly.
(SOLVED) This is a weird one. I tried everything I could find. Eventually I changed the product name from "Unit Tests (device)" to "Device Unit Tests" - removing the brackets. Now everything works. The spaces in it appear to be fine.
Previously on stackoverflow:
I've just run into this bug with two static library projects. One builds and tests using the GHUnit test runner on the device without a problem. The other projects will not install and gets this error. That means it's something thats different between these two projects. I've so far tried wiping the build directory, taking spaces out of the executable name, and various clean and builds as suggested here.
Same for me, thought it has something to do with multiple targets etc. because I changed a lot there. But it's highly possible that it's a Bug in the 3.2.2 release since I did not test extensively in this sdk version before the massive target changes in my project.
solved my issue!!!
I found out by accident that somehow a space " " found it's way into the Product Name of my app so it was called "First Second.app" instead of "FirstSecond.app". After deleting the space the issue was gone!
I changed it here:
right click on target
Get Info
Build Tab
Packaging Section
Product Name <- The name here will be used for the bundle (.app) name
Hope this helps, let me know!
Cheers,
nils
I could solved by changing project name.
[project]-[Rename] menu. "phase1 (new)" -> "pahse1"
I was getting this same error, but intermittently. I tried all the above and it still didn't work. Today I found what was causing it.
The error seems to occur when editing a xib in interface builder. If you try to run while the interface builder is open in xcode it will cause the above error. To solve just close the interface builder editor. i.e. just select a code file from your project so you are in the Source Editor.
The simplest (and probably most common cause) appears to be rebuilding without any changes.
So the simplest thing to cure it is to make a trivial change to a source file (such as adding a space, then deleting it), and then rebuilding.
If this doesn't work, feel free to try all the other answers here.
For months, I'd get this error without realizing it was due to such a simple cause. I'd usually do a Clean Build to get rid of it.
When I created ipa through terminal using xcodebuild commands, ipa created but while installing it I was getting same error. exportOptionsPlist solved my issue.
xcodebuild -exportArchive -archivePath projectPath/myapp.xcarchive -exportPath projectPath/myApp.ipa -exportOptionsPlist ProjectFolder/exportPlist.plist
In my case, Quit and restarting XCode worked.
For me the issue was related to the provisioning profile settings. The clue to this was that debug builds were installing ok, but release builds were not. I wanted to test a release build, so I ran the scheme with that build configuration.
I fixed it by duplicating the Release Configuration, then modifying those fields in the Build Settings to have the same provisioning stuff as if I am debugging it.
(Adding another build configuration will give you headaches if you are using Cocoapods however, then you'll have to modify your Podfile)
I'm getting the same thing, when installing on a iPod Touch. I can't link for the simulator (for other reasons), so can't say whether the problem occurs there.
Yes, rebuilding clean or deleting the app from the device allows me to install again. Neither are desirable, iterative solutions!
The minimal "cleaning" I've come across as a work around is manually deleting the Foo.app in the build/Debug-iphoneos directory.
it seems this is a bug in xcode 3.2.2:
iphonedevsdk
I had the same problem in Xcode 3.2.1 when I put a + in my app name. Specifically the "product name" in the build settings. It is fine to have a + in the bundle name in your Info.plist. The same probably applies to other punctuation characters.
Go to Window > Organizer > Projects > Find your project and delete derived data
I got this error intermittently while installing app using iPhone config utility on Windows7. Following solution works - Go to C:\Users\{lanusername}\AppData\Local\Temp and delete app specific folders (e.g. abc.app) and try installing app again.
I reported this bug on ICU (Windows versions) to Apple in June 2011. With the following workarounds:
The workaround is this ....
Win XP
1) Close ICU
2) Delete the temp folder: c:\Documents and Settings\[username]\Local Settings\Temp\[AppName].app
3) Delete the deploy folder: c:\Documents and Settings\[username]\Application Data\AppleComputer\MobileDevice
4) Restart ICU. Drag in the App and install normally.
============================
Win 7
1) Close ICU
2) Delete the temp folder: c:\Users\[username]\AppData\Local\Temp\[AppName].app
3) Delete the deploy folder: c:\Users\[username]\AppData\Local\Apple Computer\MobileDevice\Applications\[AppName].app
4) Restart ICU. Drag in the App and install normally.
=========================================================
I simply rebuilt my app, and that solved the issue.
I also faced the same issue. After wasting lot of time I realized that my product name has a special character "?" which cased the problem
Having the DerivedData folder at a network location caused this problem for me.
After trying everything else, I found out my workstation couldn't agree with the University server about what the time was. (It thought everything was always modified). I also had to clean for every rebuild to avoid that frustrating message.
In the end I gave up and built locally, changing Xcode > Preferences > Locations ... feeling altogether pretty dumb for having ever built over the network.
We ran into this issues on XCode_6.3.1. We were building a AppleWatch app, with an extension. We do have a bunch of Pods.. After debugging the issue for almost a bunch of hours, what we found was that there was an issue with the way a file was adde to the project..
It seems like some references to a unused file was sitting in the iPhone App, though it was used in the Watch App.. It turns out that the error XCode was showing was totally useless.
After removing this file and re adding it back to the project the project started working fine & was able to install to the device. To make it even harder to debug the issues, the debug version was installed without an issue, but was unable to install the norman version..
Make sure you add your files to the right target and, look at git history and see if there are lingering fragments that are added to the wrong target.
This is a very general error message indicating something is wrong during the validation process of the code signature. To find out the specific error, you can go to Xcode->Window->Devices and check your device log.
In my case, I have following console spew
Feb 1 18:53:07 iPod-touch installd[40] : 0x1001f8000 -[MICodeSigningVerifier performValidationWithError:]: 192: Failed to verify code signature of : 0xe8008017 (Signed resources have been added, removed, or modified)
Check on this 3rd party framework again, I found an extra CodeResources file under the framework root. Remove that file fixed the problem.

Is there a way to simulate multiple iphones using xcode/iphone sim?

I'm planning out a game that requires multiple users and I was wondering if there's a way to fire up multiple instances of the iPhone Simulator. I didn't see anything in menus or in Google search results, but I just wanted to make sure I wasn't missing anything.
It is possible but only with multiple users.
Read this: http://www.coderebel.com/2010/08/31/iphone_simulator
Assuming you have two projects (P1,P2) which you want to debug simultaneously, do as follows.
Steps to set up:
Create a new user (U2) on your Mac
Give it R/W access to P2, especially to its build folder.
Download the launcher app from the site above and copy it to Applications.
Steps to debug:
Close Xcode and the simulator if running
Launch the iPhone Launcher.app with U1.
Start Xcode with U1, load P1, start debugging.
Launch the iPhone Launcher.app with U2.
Start Xcode with U2, load P2, start debugging.
Unfortunately it's a P.I.T.A. having to change users every now and then but so far I haven't found any better solution. Hope this helps.
There is a way to do this easily without using multiple users. Keep in mind you will not be connected to the debugger though. Keep in mind the explanation below is for XCode 6+. You can skip this explanation and just scroll down to the wrapping-it-up section below.
From an answer here we can see that you can launch any simulator from command line:
open -a "iOS Simulator" --args -CurrentDeviceUDID
You can find the deviceID (as well as all your simulators) by running the xcrun simctl list command on console. It will generate a list like this. The device ID is the code in braces:
== Runtimes ==
iOS 8.3 (8.3 - 12F69) (com.apple.CoreSimulator.SimRuntime.iOS-8-3)
== Devices ==
-- iOS 8.3 --
iPhone 4s (99Z06AC6-A2D6-46E7-B4F7-BA4F5F3F39C8) (Shutdown)
iPhone 5 (K262AF11-ADD2-4FDA-ACBA-8C80DD9D4AA1) (Shutdown)
iPhone 5s (337KDC51-0A4B-47DB-8966-83562FD92C93) (Shutdown)
iPhone 6 Plus (9GK714E2-F713-4F98-A96E-C72ACD6571A8) (Shutdown)
-- iOS 8.2 --
etc continued....
Therefore to run the simulator using above as example, run this command on console:
open -n /Applications/Xcode.app/Contents/Developer/Applications/iOS\ Simulator.app/ --args -CurrentDeviceUDID '99Z06AC6-A2D6-46E7-B4F7-BA4F5F3F39C8'
We use the -n flag instead because the -a flag specifies the application to use for opening the file, while the -n flag opens a new instance of the application(s) even if one is already running. Use the man open command to know all this stuff.
Also make sure you have the correct path for your simulator.
One more thing to note, if you run the simulator like this, chances are that you have limited simulators. And since its limited, you might want to launch it without interrupting one that's already on the screen. We can solve this from this answer here where he shows you how to create a new simulator and delete one.
So wrapping it all up, here's what you do to launch them.
A) First Create a simulator before launching it.
Usage: simctl create "name" "device type id" "runtime id"
xcrun simctl create "mynewsimulator" "iPhone 6" "com.apple.CoreSimulator.SimRuntime.iOS-8-3"
You will find the runtime id from the command xcrun simctl list command I ran above. After running the above command, the deviceID will be printed on the console screen. Take note of it as you will need as the last argument to launch the simulator shown below. Let's assume this ID was 99Z06AC6-A2D6-46E7-B4F7-BA4F5F3F39C8
B) launch it
open -n /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app/ --args -CurrentDeviceUDID '99Z06AC6-A2D6-46E7-B4F7-BA4F5F3F39C8'
C) delete it once you're finished with your simulator
xcrun simctl delete 99Z06AC6-A2D6-46E7-B4F7-BA4F5F3F39C8
All this can be placed in a single .sh file for easy running.
Please note to put wait or sleep commands after each command if you decide to put all this into a sh file.
[EDIT 2017]
I see that XCode 9 will now support multiple simulators. Awaiting to see how it will all work.
As near as I can tell, not only can you not have multiple instances of the simulator running, but when time comes for actual device testing you can't have multiple instances of the debugger running either.
This means to do multi-device apps, you'll need to have a single Mac assigned to a single iPhone/touch device (or simulator instance) each running your app.
I've started looking into whether VMWare or Parallels can somehow be brought into this, but there's not much that can be done without hacking the OS.
I suggest filing a feature request with http://bugreporter.apple.com.
Another option (albeit probably overkill) if you have a Mac OS X server license is to virtualize an instance of Mac OS X Server, and run a second simulator in the VM.
Hmm...I don't think you are missing anything here. As far as I know there is no technology within the SDK that is able to emulate multiple devices -- though that would be a useful feature to have. I think your only options would be to get a second iPhone OS device, or get a friend who also has an iPhone OS device to let you use it for testing.
In XCode 4 you can run multiple instances while having both be in debug mode.
What I did was create a duplicate of my target and ran both the original and the duplicate. If you're using the output window you can toggle which output you are looking at.
Follow these steps to test your app.
You have to do one thing for whole process first :
Go to Project - > Edit Project Settings -> tick on option - Build independent targets in parallel.
Debug code that will create your app in simulator For Example your App name is - Instance
Close Simulator
Go to Project->New Target -> Instance2
Add "Bundle display name : Instance2" in Instance2.info.plist file
Set Executable Name : Instance2
Select Instance2 Target -> Go to Project -> Set Active Target -> Instance2
Build with Instance2
Note : Do all carefully otherwise you have to reset your simulator
For Reset Simulator -> Run Simulator -> iPhone Simulator -> Reset Content & Settings...
Now You have two apps in simulator and you can test app on all instance.
Hope it will help you :)
I managed to get it to work combining answer by Ivsty with this one.
Basically, what you do is create two users (A and B), run simulators in each of them, run VNC server on user B, and then connect from user A to access screen B without needing to switch users.
Yes, now it's possible and is also quite easy.
The only thing you need is xctool, the build tools from Facebook and a ruby gem. The ruby gem helps to create/destroy the simulator needed during the test.
You can read the full documentation on this link:
https://github.com/plu/parallel_ios_tests
I'm using this approach and I run my test on 4 iOS simulator on the same time.
Supported from Xcode 9 on.
(Source: WWDC 2017)