The iOS Simulator shares ports with the host machine. The iOS build will select a log server port based on the <log-server-port> in the tiapp.xml or based on the hash of the app id using the following logic:
Because we only allow a possible 50,000 possibilities, the likelihood of a collision is high. In my tests, it's about 5%. The solution to the collisions is to just allow manual override by setting a <log-server-port> in the tiapp.xml.
The next problem is what if the app id hash port resolves a port number used by another piece of software? Say you have MongoDB installed and it's listening on port 27017. It's entirely possible Titanium will pick 27017.
The current iOS build logic tries to be smart. It starts a Node.js server listening on the selected port and if it can't bind to it, then that means some other app already has bound to the port. It will then select a random port. I knew at design time that random ports will break the differential build system, but figured it would only happen if there was a collision.
Turns out that's not quite accurate. If you build an app for the sim and then rebuild our app while leaving the previous build running in the sim, the iOS build will detect the desired port is not available because the iOS app is currently listening on it. This causes the iOS build to randomly select a port.
The port number gets written to the Xcode project. Since it will generate a new random port every build (as long as the sim and previous build is running), the iOS build detects the Xcode project is different and forces a full rebuild.
We have 5 solutions:
1. Don't select a random port. Just use the port regardless if it's in use. Cons: high chance of port collisions and false positives, the iOS app will fail to bind to it and there will be no logs and no warning.
2. Don't select a random port. If the port is already in use, try connecting to it and see if it's the app we're trying to build and if so, then proceed with the build. If the port is being used by something such as a web server, it will be expecting data, but because the log server clients do not send data, we end up in a stalemate. We would need to add a timeout. Cons: the timeout will pause the build by ~1 second.
3. Allow random ports if the desired port is unavailable. Pass the GCC_PREPROCESSOR_DEFINITIONS="TI_LOG_SERVER_PORT=XXXX" directly into xcodebuild instead of baking it into the Xcode project. Cons: you will run in a loop where the build will alternate between the hashed port and a random one, we would need to force xcodebuild to re-compile using the new port value.
4. Write the port to a file (could be any file) and bundle it with the app. Avoids the Xcode project and xcodebuild. If the file does not exist or is empty, then logging is disabled. Cons: easy to accidentally ship with the app and enable logging in production.
5. Pass the port number in as an argument when we call simctl launch. We would still bake the DISABLE_TI_LOG_SERVER=1 into the Xcode project for dist builds. Cons: ioslib currently does not support passing arguments into simctl launch, subsequent manually launching the app will not have the argument.
I think option 1 and 3 are not too good. Option 2 is not so great. Option 4 is not too bad. https://www.youtube.com/watch?v=vm-MrkoJPC8