[TIMOB-17335] iOS8: Add support for Share Extensions
GitHub Issue | n/a |
---|---|
Type | Epic |
Priority | Medium |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2016-03-28T14:48:33.000+0000 |
Affected Version/s | n/a |
Fix Version/s | Release 5.3.0 |
Components | iOS |
Labels | ios8, notable, roadmap |
Reporter | Ingo Muschenetz |
Assignee | Chris Barber |
Created | 2014-07-15T21:11:33.000+0000 |
Updated | 2016-05-23T21:47:28.000+0000 |
Description
iOS 8 allows developers to add extensions to the Share infrastructure.
We're going to put this on hold for now. Not sure how this can be implemented in Titanium at this time. The way to build Extensions, to make a long story short, is by creating a new target in an Xcode project and then subclassing some predefined classes.
Since the WatchKit will probably work in a similar way (set of API's plus new target) maybe it's good to start investigating [App Extensions](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/) and the extension point *Today* in particular so that when WatchKit is published we may have tackled some of the challenges?
I'm guessing that you would create a set of files in your application, perhaps in a folder (perhaps that's in a specially-named "extensions" folder). These would implement certain classes as required. When performing the build, the CLI would then know how to generate the proper Xcode targets for this. Thoughts?
+1 to start thinking about it right now
this is important !! any hack around it for now ?
First of all, this is going to be a huge limitation if appcelerator cannot implement because of the major user engagement from these widgets. It enables uploads right from iPhoto app or other "file association" ios behavior... Former plist document handling zone.... Anyone needing this really needs it. So I cracked open a generated titanium output Xcode project in Xcode. I inserted a new "share extension" in the app targets. I was then able to write some bit of swift code and save and compile it. So flawlessly does the sharing work I cannot do without this. Of course the Xcode file is now been manually edited and it will be overwritten. Furthermore, enabling swift broke some older titanium code, and the original titanium project no longer ran from Xcode. Conclusion: this should be a high priority because demand for this functionality is already high, note the mass of non titanium apps available already that save email attachments etc. Please do implement this Xcode target type ... Titanium already handles ios targets for iPad and iPhone, adding the extension should not be too hard.
[~Spaceghost] Thank you for your input. I think there are two pieces here.
As you mention, it should be relatively trivial for us to allow packaging a native extension a developer has implemented.
The second (more challenging aspect) is how should a developer indicate that they wished to create a native extension in a Titanium Project. I'm assuming you'd either create a separate project, or indicate that a subset of your files was used for the share extension.
I would keep it in the same project. Maybe a dedicated folder under Resources?
One file per extension? One sub-folder per extension? Then the question of how you do it via Alloy.
/platform/ios/extensions/
I don't have enough insight in how extenions work to say how I'd like to have it structured. Is it a single view/controller? Is it like how you do a service?
Looking at the doc: https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/NotificationCenter.html#//apple_ref/doc/uid/TP40014214-CH11-SW1 I think it would be ideal to have: Today / Share / Action/etc; Extensions to be part of the App (not a separate project).
I think first priority is making extensions "possible", even if its a native extension. Then second step is figuring out if its feasible to run an extension via the JS runtime...so probably shouldn't be worried about auto-layout for the first priority since you'd have to build the extension in native code anyway.
Agree with Rick, I'm happy with a workaround, even just a clean way to inject a small bit of swift code into the output Xcode file pre-compile somehow, then CLI can do its thing. AFAIK, to deploy to the Apple AppStore, the extension *must* be in the Xcode project and the same app as the "parent" application. It is after all an "app extension" and logically Apple do not intend it to be treated as a separate entity or independent build-able target. I'm assuming to build for iTunes deployment, these changes would have to be made by Titanium before signing the upload package. That said, I did make an extension work using my Titanium output Xcode project and creating a swift app extension. Well the app extension worked, but using swift broke Appcelerator libraries must be compatibility issues there as well.
Hi Team, I wish i screenshotted my Xcode project it looked very simple to implement. Just a few files were created in a folder and a new target in the Xcode project root. So from the Titanium perspective this would be like having an extra checkbox for iOS Targets [x] iPhone [x] Contains iOS extension Just take any Xcode project output from Titanium and open in Xcode6. Then follow the instructions here and create a swift widget: http://www.glimsoft.com/06/28/ios-8-today-extension-tutorial/ I needed a "Share" widget to access photos and webpages and email attachments etc. I was able to use my Titanium project as the "Base" which showed clearly the file layout. You may have some compile issues perhaps if you have certain Ti.xx modules but I was able to just comment out the offending lines and continue to build my extension (While of course knowing my App would be rendrered useless so I did not worry about modding ti code.
[~cbarber], as discussed about in ios extensions. Considering this particular share extension has so many listeners, we may consider implementing it as a template flag that we discussed before.
any news on this one... what's the ETA ?
[~pilo] Share extensions should work. Creating new share extensions are currently not supported by the
appc new
orti create
commands. You have to manually create the Xcode project, add the share extension as a target, then add the extension and target to the tiapp.xml. I can't find the docs on how to do this. You can find an tiapp.xml example for a WatchKit extension here: https://docs.appcelerator.com/platform/latest/#!/guide/Integrate_a_WatchKit_App_Built_in_Xcode. You simply need to ignore the WatchKit app target and only add the share extension target.I've done some further investigation on this. We had a project with Extensions that work with tisdk 3.2 beta back when tooling was first working on extensions. We have migrated to Ti 5.0.2 and 5.1.2 and the extensions are no longer included in the IPA. They show in the generated xcode project, but do not get included into the build. I've published a minimum viable version of the app to github at https://github.com/jeffbonnes/appc-doc-provider-example. The branch that works using TiSDK 3.2 Beta is at https://github.com/jeffbonnes/appc-doc-provider-example/tree/ti-sdk-2.5.2beta. The upgraded version that doesn't work is on branch https://github.com/jeffbonnes/appc-doc-provider-example/tree/ti-sdk-5.x. A summary of the changes made to tiapp.xml for V5 of the SDK is at https://github.com/jeffbonnes/appc-doc-provider-example/commit/7be8db3b8ee0a2fa4bdc25a7913966e300d0bad1. Interesting, the expected appex files that should be included in the IPA are in the build/Products directory, but not in the IPA. I'm happy to provide any additional information, but right now, Extensions are not working on iOS.
We focused testing on watch extensions, though any extension should work. FWIW, we have limited support for non-watch extensions and app groups. Regardless, it's possible that share extensions require a different build phase or dependency wire up in the Xcode project. The best place to start is to build the Titanium app with your share extension and open the generated Xcode project in the
build/iphone
directory. Next create a new native iOS app with a share extension. With both Xcode projects open, compare the build phases, dependencies, and capabilities. Is there any discrepancies? If so, what?I had a look at the generated xcode project compared to a standard xcode project with extensions and can see the issue. All the code for the extensions are in the generated xcodeproject, but they are not listed in the 'Embedded Binaries' section of the General tab of the main target. When I added all the extensions in the Embedded Binaries section and ran on device from xcode, it worked as expected.
Is there a workaround to get share extension bundled again in the meantime? Even if it involves manual intervention with xcode - got an app partly broken since updating SDK.
I've gotten this to work with a simple Document Provider extension by modifying the /iphone/cli/commands/_build.js script in the Titanium SDK. I tested with version 5.2.0.GA but this should also work with the most current code on the 5_2_X branch on GitHub. Around line 3131 of iphone/cli/commands/_build.js reads:
This needs to be modified to:
Adding
|| targetInfo.isExtension
to the if statement seems to ensure that the .appex files from the extensions are added to the Embedded Binaries of the XCode project. [~cbarber] - looking at /iphone/cli/commands/_build.js file in master, it now reads:I would think this will mean that all non-watch 2 extensions will not work. I think the new code should read:
Is there an example of a Extension that should not appear in the Embedded Binaries section?
Excellent news [~jeffbonnes]!
Great efford [~jeffbonnes]. Can you submit a Pull Request on Github so people can use it from the Core in future versions? Would greatly appreciate that!
[~jeffbonnes] If I'm understanding you correctly, you're saying we should add
|| targetInfo.isExtension
. However adding that is pointless since the code can be simplified to your last snippet:That makes sense to me. That if-block won't even get touched if it's not an extension and if it's not a WatchApp v2 or newer, then it's a WatchApp v1 or an extension. So, if I'm following you, then https://github.com/appcelerator/titanium_mobile/pull/7890 should be changed to reflect the suggested lines above and not add
|| targetInfo.isExtension
.[~cbarber] Makes sense, updated PR.
Agree 100% - thanks guys.
I'd love to see this important fix in a release earlier than 5.4.0, if possible.
Me too.
[~hansknoechel] can you build a back port for 5.3.X for this? Don't merge yet though.
PR (5_3_X): https://github.com/appcelerator/titanium_mobile/pull/7968
Backport merged. [~hansknoechel] are you able to quickly have the test app for QE with regards to this fix?
Steps to Test
1. Create a native Titanium App *appc new* 2. Example app name istitaniumShare
, thecom.appcelerator.sg.titaniumShare
3. Open Xcode and create new projectFile->New Project->Other->Empty
4. Name ittitaniumShare
4.File->New->Target->Application Extension->Share Extension
5. Name ittitaniumShare
and change Organization Identifier tocom.appcelerator.sg.titaniumShare
so that the Bundle Indemnifier iscom.appcelerator.sg.titaniumShare.titaniumShare
6. If you wish, you can activate scheme when prompted, it doesn't matter. 7. Create folderextensions
in Titanium Project folder and copy the Xcode extension project into it. 8. In tiapp.xml, include these properties in10. *appc run -p ios*
Expected Result
Open Safari in device or simulator. Navigate to any website. Click the share button-> more, you will see titaniumShare. Before this PR, this is not shown. Titanium sample app: https://github.com/cheekiatng/titaniumShare (Although the sample app is written using Titanium CLI, It's recommended to use appc as stated in the reproduction steps)This is nice! [~cng] how would a developer be able to hand the file over to the Titanium iOS app? It would be great to build a sample app around that but I need some more context.
Thanks Chee Kiat Ng. Fokke's question makes lot of sense in this case, as biggest issue from this point is that the share extension has to completely handle by itself the file received and get the user back to the host app from where is sharing the content. This is normally done by creating a native framework shared by the containing app and the extension, so both have the necessary code to handle the file. But I can't see how a share extension could share a framework with a titanium project. So, in my understanding, there are only two options: 1) write native code in the share extension to handle the file received or 2) launch the ti app and let it handle the file. This is a big challenge, as Apple expects that the containing app (the ti app, to be clear) is not opened during the process at all. Precisely, the share extension's design makes unnecessary to open the app and doing so is considered a bad practice, but I can't see how this could be avoided with in titanium projects. The only option would be, as mentioned, implement the logic in the extension, which I guess is a no-go for most ti developers (in our case, it would mean to rewrite most of the app to native). At least in my case, I would accept option 2), at least until something better can be achieved with titanium. In this sense, this link may help on how to send the file to the containing app from the extension: http://stackoverflow.com/questions/32228182/code-to-share-file-path-file-between-a-share-extension-and-ios-app Also I think both apps (the app and the extension) must be part of an App Group, as explained here https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW19 I'm trying by myself, but couldn't make it work yet. I'll comment here if get something. Hope it helps.
We have a different situation as our Extension is a Document Provider, but we did have to write Native Code in the Extension to do quite a lot. It did duplicate a lot of logic we have in our Ti app.
Thanks, Jeff, good to know. I will implement also the Document Provider extension, so any advice is more than welcome. Is that any public example we can look at?
[~jaraen] Maybe we can wrap [this solution via nsuserdefaults](http://stackoverflow.com/a/33795269/4626813) in a Swift/Obj-C lib and Ti API to pass data to the Titanium iOS app for processing, which would then notify the extension with the result so it can update the extension UI (with the error or saying it has been done)?
Yes I think this is pretty exciting as well. I hope the above merged PR , as well as the related today extension helps to open more possibilities of the usage of extensions with titanium SDK. Thanks everyone for your input. Will appreciate very much if we don't clutter in this ticket, and create new specific tickets instead of improvements or new features with regards to ios extensions. And of course, PRs are very welcomed :)
That's the plan, Fokke. I should be able to spend some time on it this week, I'll let you know.
@jaraen - are your extensions also setup to access the application groups? A copy of my Entitlements.plist that works in my Titanium project is below:
thanks, @jeffbonnes sure, I did that and reviewed several times. There's no error or pending fixes in the extension project. However, if I open in xCode the project generated by titanium, the group appears in red. There are no errors, the group name is red. Pretty weird... Worths saying that I've tried with two different projects and had same result. A couple of questions: are you able to run the extension on simulator? Should it work without setting any profile in the extension tag? If so, are you launching the project specifying any provisioning profile? Or do you trust in default xcode generated profiles? Thanks!
Closing as implemented.