iOS and macOS App Extensions with Delphi
[SHOWTOGROUPS=4,20]
November 15, 2018 Allen Drennan
In this article we are going to cover how to package iOS and macOS Application Extensions with your Delphi developed iOS and macOS application and interact with the Application Extension from Delphi using the Application Groups API.
Introduction
There are numerous features on iOS and the Mac that are only available using Для просмотра ссылки Войдиили Зарегистрируйся. App Extensions are essentially background processes or plugins that are bundled along with your main host application and installed simultaneously when your app is initially installed. Delphi doesn’t have any way to directly build App Extensions, but you can create them in XCode and you can consume them, bundle them and interact with them in your Delphi project.
Why would you need Application Extensions? Well there are many API capabilities on iOS and macOS that are only available through App Extensions. For example, you can use the ReplayKit API directly from your Delphi app to capture your own Delphi app UX experience and either record it or stream it over the web. However, as soon as you return to the home screen on iOS, your application is placed into the background and ReplayKit no longer provides the callback. If you want to capture the entire UX experience of the iOS device you need a background process. Apple created the concept of a Broadcast Upload App Extension which uses the ReplayKit APIs in the background to capture the entire device UX. This capability is only available from an Application Extension.
There are many other capabilities only available via App Extensions, such as Today widgets and Social sharing extensions.
Creating App Extensions
XCode provides templates to ease the process of creating an App Extension. You simply create a new Project in XCode and then add a new Target for the extension(s) you want to include. While the template provides no practical code, it is a working App Extension that you can manipulate and test the ideas presented in this article.
Apple expects that all App Extensions will use a Bundle Id that is an expansion of host application’s Bundle Id. So if your Delphi host application’s Bundle Id is com.company.myapp then your App Extension’s Bundle Id needs to be com.company.myapp.myextension.
Once you build the project in XCode, you only need to copy the App Extensions from the Mac over to your Windows computer where your Delphi project resides. Essentially it is as simple as locating your XCode bundle .app folder and copying the entire \PlugIns subfolder and all related files to a location in your existing Delphi project.
Once you have copied the extension(s), you only need to add these files to your Delphi Deployment Manager. They must target the .\PlugIns folder in your deployed project. When you Build and Run your Delphi application, your App Extensions will automatically be installed along with your main host application. It is really that simple.
For security reasons, on iOS and macOS your application is essentially Для просмотра ссылки Войдиили Зарегистрируйся and it is prevented from interacting directly with other processes. This is also true of App Extensions and their host application, even if they share a Bundle Id and even if they are part of the same Bundle.
In order to initialize or interact between your Delphi created host application and the extension you need to use some form of IPC (inter-process communication). On iOS and macOS there is a mechanism known as Для просмотра ссылки Войдиили Зарегистрируйся that provides various IPC related capabilities. Apple actually uses XPC to launch and configure App Extensions internally. However, for developers on iOS, Apple provides a set of APIs known as Для просмотра ссылки Войди или Зарегистрируйся which essentially uses the XPC APIs to provide a shared space for multiple App Extensions and the host application in the same bundle to interact and exchange information.
In order to use Application Groups you need to enable App Groups in the Apple Develop Portal and create a new App Id. First you create an App Group in the Apple Developer portal and provide a properly formatted name. This should be in the form of group.com.company.myapp. Then you create a new App Id for your main host application and for each of your App Extensions. They should each be configured to use App Groups and you should choose the Application Group name you created (ex: group.com.company.myapp). In Delphi you need to make sure your project’s Provisioning Profile (under Project Options) is configured correctly.
Delphi will automatically include the new Entitlements from the Provisioning Profile for the Application Group and Delphi will automatically add the Entitlement to your Bundle.
In order to share settings and data between your main host application and the App Extension, you need to use the NSUserDefaults APIs and initialize it with the initWithSuiteName() API. This is done in every host application and App Extension that wants to exchange data.
Delphi doesn’t expose this specific API, so for our purposes we will create a small wrapper to expose it:
Then to setup our shared settings from Delphi we first initialize the NSUserDefaults using our Application Group name along with the initWithSuiteName() API. You can only use theinitWithSuiteName() API to create a shared NSUserDefaults and all other related APIs will instead initialize a sandboxed NSUserDefaults. We then call setObject() or one of the various APIs available within NSUserDefaults to update a specific key/value pair. You can pass as many individual settings as you want, but in order to update all other App Extensions about the changes you must call the synchronize() API.
[/SHOWTOGROUPS]
November 15, 2018 Allen Drennan
In this article we are going to cover how to package iOS and macOS Application Extensions with your Delphi developed iOS and macOS application and interact with the Application Extension from Delphi using the Application Groups API.
Introduction
There are numerous features on iOS and the Mac that are only available using Для просмотра ссылки Войди
Why would you need Application Extensions? Well there are many API capabilities on iOS and macOS that are only available through App Extensions. For example, you can use the ReplayKit API directly from your Delphi app to capture your own Delphi app UX experience and either record it or stream it over the web. However, as soon as you return to the home screen on iOS, your application is placed into the background and ReplayKit no longer provides the callback. If you want to capture the entire UX experience of the iOS device you need a background process. Apple created the concept of a Broadcast Upload App Extension which uses the ReplayKit APIs in the background to capture the entire device UX. This capability is only available from an Application Extension.
There are many other capabilities only available via App Extensions, such as Today widgets and Social sharing extensions.
Creating App Extensions
XCode provides templates to ease the process of creating an App Extension. You simply create a new Project in XCode and then add a new Target for the extension(s) you want to include. While the template provides no practical code, it is a working App Extension that you can manipulate and test the ideas presented in this article.
Apple expects that all App Extensions will use a Bundle Id that is an expansion of host application’s Bundle Id. So if your Delphi host application’s Bundle Id is com.company.myapp then your App Extension’s Bundle Id needs to be com.company.myapp.myextension.
Once you build the project in XCode, you only need to copy the App Extensions from the Mac over to your Windows computer where your Delphi project resides. Essentially it is as simple as locating your XCode bundle .app folder and copying the entire \PlugIns subfolder and all related files to a location in your existing Delphi project.
Once you have copied the extension(s), you only need to add these files to your Delphi Deployment Manager. They must target the .\PlugIns folder in your deployed project. When you Build and Run your Delphi application, your App Extensions will automatically be installed along with your main host application. It is really that simple.
Exchanging data with your App ExtensionThe Для просмотра ссылки Войдиили Зарегистрируйся tool makes adding and removing files from the Deployment Manager settings for your Delphi project much easier.
For security reasons, on iOS and macOS your application is essentially Для просмотра ссылки Войди
In order to initialize or interact between your Delphi created host application and the extension you need to use some form of IPC (inter-process communication). On iOS and macOS there is a mechanism known as Для просмотра ссылки Войди
In order to use Application Groups you need to enable App Groups in the Apple Develop Portal and create a new App Id. First you create an App Group in the Apple Developer portal and provide a properly formatted name. This should be in the form of group.com.company.myapp. Then you create a new App Id for your main host application and for each of your App Extensions. They should each be configured to use App Groups and you should choose the Application Group name you created (ex: group.com.company.myapp). In Delphi you need to make sure your project’s Provisioning Profile (under Project Options) is configured correctly.
Delphi will automatically include the new Entitlements from the Provisioning Profile for the Application Group and Delphi will automatically add the Entitlement to your Bundle.
1 2 3 4 | <key>com.apple.security.application-groups</key> <array> <string>group.com.company.myapp</string> </array> |
Using App Groups from your Delphi applicationYou should not add this Entitlement manually or your application will not function because of the duplicate key.
In order to share settings and data between your main host application and the App Extension, you need to use the NSUserDefaults APIs and initialize it with the initWithSuiteName() API. This is done in every host application and App Extension that wants to exchange data.
Delphi doesn’t expose this specific API, so for our purposes we will create a small wrapper to expose it:
1 2 3 4 5 6 7 8 9 10 11 12 | uses iOSapi.Foundation, Macapi.Helpers, Macapi.ObjectiveC; type MissingNSUserDefaults = interface(NSUserDefaults) ['{57042F99-BD77-4E25-9AE1-B8F0C6776A18}'] function initWithSuiteName(suitename: NSString): Pointer; cdecl; end; TMissingNSUserDefaults = class(TOCGenericImport<NSUserDefaultsClass, MissingNSUserDefaults>) end; |
Then to setup our shared settings from Delphi we first initialize the NSUserDefaults using our Application Group name along with the initWithSuiteName() API. You can only use theinitWithSuiteName() API to create a shared NSUserDefaults and all other related APIs will instead initialize a sandboxed NSUserDefaults. We then call setObject() or one of the various APIs available within NSUserDefaults to update a specific key/value pair. You can pass as many individual settings as you want, but in order to update all other App Extensions about the changes you must call the synchronize() API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var Defaults: NSUserDefaults; SharedSettings: MissingNSUserDefaults; begin { Init with the proper Application Group suite name } Defaults := TNSUserDefaults.Alloc; SharedSettings := TMissingNSUserDefaults.Wrap((Defaults as ILocalObject).GetObjectID); SharedSettings.initWithSuiteName(StrToNSStr('group.com.company.myapp')); { Save SomeKey/SomeValue to the shared settings } SharedSettings.setObject( (StrToNSStr('SomeValue') as ILocalObject).GetObjectID, StrToNSStr('SomeKey') ); { Update the settings } SharedSettings.synchronize; end; |
[/SHOWTOGROUPS]