Did you know that it’s possible to load and use 3rd Party Frameworks in your Xojo iOS projects? There’s quite a number of good projects out there, many of which are on sites like GitHub and freely available for use in your projects. If you’re familiar with Declares in iOS, loading a 3rd Party framework requires just a couple of extra lines of code and a CopyFilesStep.
Last year at XDC 2018, Jérémie Leroy talked about making sure your screenshots mimicked the Apple method so that the date was always Jun 9th, the time was always 9:41 AM, the battery always shows as full and the WiFi strength always shows full. It got me thinking that it might be handy to be able to make the simulator always show those values when you do a debug run so that you don’t need to think about it when you are ready to start taking screenshots and movies of your app. One way to do that is to build & run project like SimulatorStatusMagic on the simulator before running your project, but it would be more useful if it was automatic.
Build the Framework
First of all, go to the SimulatorStatusMagic Github page and clone or download the project. Just like Xojo iOS development, you’ll need Xcode for this step. After you’ve downloaded the project, double-click on the SimulatorStatusMagic.xcodeproj file to open it in Xcode. When the project opens, change the target to SimulatorStatusMagiciOS and build it by either pressing CMD-B or pressing the Play button. Once the build is complete, go to the project navigator, scroll down to the bottom and open the Products group to reveal the built parts of this project. The only item we’re concerned with here is the file named SimulatorStatusMagiciOS.framework. Right-click on it and select Show in Finder.
Build the Project
Let’s start off by making sure the framework will be available to your project at runtime.
- Create a folder on your drive named SimulatorStatusMagic and copy the framework file that you just built into it.
- Launch Xojo and create a new iOS project. Save the project into that folder as well.
- To make sure the framework will be available to your project when debugging, go to the iOS target in the Xojo navigator, right-click and select Build Step > Copy Files. Make sure the step is between the Build step and the Sign step.
- Drag the SimulatorStatusMagiciOS.framework file from the Finder into the Copy Files Step.
- In the Xojo inspector, set Applies To to “Debug” and Destination to “App Parent Folder”.
Now let’s make it so you can access the framework! We’re going to add this code in the App.Open event so that the status bar gets set up before you do anything else.
Getting the framework to load is fairly straightforward:
#If DebugBuild Declare Function dlopen Lib "/usr/lib/libSystem.dylib" (name As CString, flags As Int32) As Ptr Call dlopen("@executable_path/SimulatorStatusMagiciOS.framework/SimulatorStatusMagiciOS", 1 Or 8) #EndIf
That magic string “@executable_path” gets translated into “wherever the current application currently is” at runtime. Now this just loads the framework. We still need to hook up the methods and properties. Note: If you’re working with a framework that “activates itself” like the one that comes with Reveal (an excellent tool for tracking down iOS layout issues), this is as far as you would need to go.
To figure out what we need to do next, we need to look at the documentation and header files that come with SimulatorStatusMagic. Go back to Xcode and look at the navigator. What we’re looking for is a header file (with a .h extension) which has the definitions of each of the methods and properties which are available in this framework. The only file that meets this criteria (and the one that all the others seem to point to) is named SDStatusBarManager.h. There’s a bit of functionality available here, but the framework is set up to use the Apple recommended settings by default, so all we’re going to do here is call the enableOverrides method to activate it.
Go back to Xojo and update App.Open event:
#If DebugBuild Declare Function dlopen Lib "/usr/lib/libSystem.dylib" (name As CString, flags As Int32) As Ptr Call dlopen("@executable_path/SimulatorStatusMagiciOS.framework/SimulatorStatusMagiciOS", 1 Or 8) // Start by creating a pointer to the SDStatusBarManager class itself Declare Function NSClassFromString Lib "Foundation" (clsName As CFStringRef) As Ptr Dim smclass As Ptr = NSClassFromString("SDStatusBarManager") // Next, we need a pointer to the shared instance of the SDStatusBarManager class Declare Function sharedInstance Lib "Foundation" Selector "sharedInstance" (clsref As Ptr) As Ptr Dim smclassShared as Ptr = sharedInstance(smclass) // Last, turn on the overrides // NOTE: We're specifically NOT using the actual lib name here. // This is just to satisfy the Xojo linker. The correct framework will be used at runtime. Declare Sub enableOverrides Lib "Foundation" Selector "enableOverrides" (obj As Ptr) enableOverrides(smclassShared) #EndIf
Now if you run the project, when it opens the status bar automatically changes to the recommended defaults!
Please Note: These changes persist until the simulator device that you are running on is completely erased. If you need to disable it, you can do that with the disableOverrides method.
After posting this article, it was brought to my attention that I’d forgotten to show you how to sign the frameworks so you can build for the app store. To do that, you’ll need to add a script build step to your project, just after the Copy Files step you added above. The step can probably be set to Applies To: Release. The code should look like this:
// Replace the text in the signingIdentity property with your own Dim signingIdentity As String = "iPhone Distribution: Your Company (XXXXXXXXXX)" Dim code As Integer Dim cmd As String Dim result As String Dim builtApp As String builtApp = CurrentBuildLocation + "/" + ReplaceAll(CurrentBuildAppName, " ", "\ ") // Get a list of all frameworks, one per line cmd = "ls -d1 " + builtApp + "/*.framework" result = Trim(DoShellCommand(cmd, 30, code)) // If there was no error (like none being there), sign each one If code = 0 Then Dim frameworks() As String = split(result, chr(13)) For i As Integer = 0 To UBound(frameworks) frameworks(i) = ReplaceAll(frameworks(i), " ", "\ ") cmd = "/usr/bin/codesign -fs """ + signingIdentity + """ " + frameworks(i) Result = DoShellCommand(cmd, 30, code) // If the sign fails, print the error and stop the build If code <> 0 Then print Result cancelBuild End If Next i End If