Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-17335] iOS8: Add support for Share Extensions

GitHub Issuen/a
TypeEpic
PriorityMedium
StatusClosed
ResolutionFixed
Resolution Date2016-03-28T14:48:33.000+0000
Affected Version/sn/a
Fix Version/sRelease 5.3.0
ComponentsiOS
Labelsios8, notable, roadmap
ReporterIngo Muschenetz
AssigneeChris Barber
Created2014-07-15T21:11:33.000+0000
Updated2016-05-23T21:47:28.000+0000

Description

iOS 8 allows developers to add extensions to the Share infrastructure.

Comments

  1. Pedro Enrique 2014-08-22

    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.
  2. Fokke Zandbergen 2014-09-10

    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?
  3. Ingo Muschenetz 2014-09-10

    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?
  4. Alexey Chulochnikov 2014-09-16

    +1 to start thinking about it right now
  5. erez pilosof 2014-09-18

    this is important !! any hack around it for now ?
  6. John McMahon 2014-10-19

    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.
  7. Ingo Muschenetz 2014-10-20

    [~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.

  8. Fokke Zandbergen 2014-10-20

    I would keep it in the same project. Maybe a dedicated folder under Resources?
  9. Ingo Muschenetz 2014-10-20

    One file per extension? One sub-folder per extension? Then the question of how you do it via Alloy.
  10. Rick Blalock 2014-10-20

    /platform/ios/extensions/
  11. Fokke Zandbergen 2014-10-20

    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?
  12. Joseph Sachs 2014-10-20

    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).
  13. Rick Blalock 2014-10-20

    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.
  14. John McMahon 2014-10-20

    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.
  15. John McMahon 2014-10-20

    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.
  16. Chris Bowley 2014-10-21

  17. Chee Kiat Ng 2015-09-11

    [~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.
  18. erez pilosof 2015-10-07

    any news on this one... what's the ETA ?
  19. Chris Barber 2015-10-07

    [~pilo] Share extensions should work. Creating new share extensions are currently not supported by the appc new or ti 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.
  20. Ivan Skugor 2015-12-17

  21. Jeff Bonnes 2016-01-14

    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.
  22. Chris Barber 2016-01-14

    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?
  23. Jeff Bonnes 2016-01-18

    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.
  24. Neil H 2016-02-23

    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.
  25. Jeff Bonnes 2016-03-18

    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:
        if (targetInfo.isWatchAppV1Extension ) {
        	addEmbedBuildPhase.call(this, 'Embed App Extensions', null, 13 /* type "plugin" */);
        } else if (targetInfo.isWatchAppV2orNewer) {
        	addEmbedBuildPhase.call(this, 'Embed Watch Content', '$(CONTENTS_FOLDER_PATH)/Watch', 16 /* type "watch app" */);
        }
        
    This needs to be modified to:
        if (targetInfo.isWatchAppV1Extension || targetInfo.isExtension) {
        	addEmbedBuildPhase.call(this, 'Embed App Extensions', null, 13 /* type "plugin" */);
        } else if (targetInfo.isWatchAppV2orNewer) {
        	addEmbedBuildPhase.call(this, 'Embed Watch Content', '$(CONTENTS_FOLDER_PATH)/Watch', 16 /* type "watch app" */);
        }
        
    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:
        if (targetInfo.isWatchAppV2orNewer) {
        	addEmbedBuildPhase.call(this, 'Embed Watch Content', '$(CONTENTS_FOLDER_PATH)/Watch', 16 /* type "watch app" */);
        }
        
    I would think this will mean that all non-watch 2 extensions will not work. I think the new code should read:
        if (targetInfo.isWatchAppV2orNewer) {
        	addEmbedBuildPhase.call(this, 'Embed Watch Content', '$(CONTENTS_FOLDER_PATH)/Watch', 16 /* type "watch app" */);
        } else {
        	addEmbedBuildPhase.call(this, 'Embed App Extensions', null, 13 /* type "plugin" */);
        }
        
    Is there an example of a Extension that should not appear in the Embedded Binaries section?
  26. Fokke Zandbergen 2016-03-18

    Excellent news [~jeffbonnes]!
  27. Hans Knöchel 2016-03-18

    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!
  28. Chris Barber 2016-03-28

    [~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:
        if (targetInfo.isWatchAppV2orNewer) {
        	addEmbedBuildPhase.call(this, 'Embed Watch Content', '$(CONTENTS_FOLDER_PATH)/Watch', 16 /* type "watch app" */);
        } else {
        	addEmbedBuildPhase.call(this, 'Embed App Extensions', null, 13 /* type "plugin" */);
        }
        
    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.
  29. Hans Knöchel 2016-03-28

    [~cbarber] Makes sense, updated PR.
  30. Jeff Bonnes 2016-03-28

    Agree 100% - thanks guys.
  31. Daniel Kunzler 2016-04-26

    I'd love to see this important fix in a release earlier than 5.4.0, if possible.
  32. Dirlei Dionísio 2016-04-27

    Me too.
  33. Chee Kiat Ng 2016-04-27

    [~hansknoechel] can you build a back port for 5.3.X for this? Don't merge yet though.
  34. Hans Knöchel 2016-04-27

    PR (5_3_X): https://github.com/appcelerator/titanium_mobile/pull/7968
  35. Chee Kiat Ng 2016-04-29

    Backport merged. [~hansknoechel] are you able to quickly have the test app for QE with regards to this fix?
  36. Chee Kiat Ng 2016-05-03

    Steps to Test

    1. Create a native Titanium App *appc new* 2. Example app name is titaniumShare, the in tiapp.xml will be something like com.appcelerator.sg.titaniumShare 3. Open Xcode and create new project File->New Project->Other->Empty 4. Name it titaniumShare 4. File->New->Target->Application Extension->Share Extension 5. Name it titaniumShare and change Organization Identifier to com.appcelerator.sg.titaniumShare so that the Bundle Indemnifier is com.appcelerator.sg.titaniumShare.titaniumShare 6. If you wish, you can activate scheme when prompted, it doesn't matter. 7. Create folder extensions in Titanium Project folder and copy the Xcode extension project into it. 8. In tiapp.xml, include these properties in section
            <extensions>
              <extension projectPath="extensions/titaniumShare/titaniumShare.xcodeproj">
                <target name="titaniumShare">
                  <provisioning-profiles>
                    <device/>
                    <dist-appstore/>
                    <dist-adhoc/>
                  </provisioning-profiles>
                </target>
              </extension>
            </extensions>
        
    10. *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)
  37. Fokke Zandbergen 2016-05-03

    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.
  38. Javier Rayon 2016-05-03

    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.
  39. Jeff Bonnes 2016-05-03

    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.
  40. Javier Rayon 2016-05-03

    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?
  41. Fokke Zandbergen 2016-05-04

    [~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)?
  42. Chee Kiat Ng 2016-05-04

    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 :)
  43. Javier Rayon 2016-05-04

    That's the plan, Fokke. I should be able to spend some time on it this week, I'll let you know.
  44. Javier Rayon 2016-05-11

  45. Jeff Bonnes 2016-05-12

    @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: com.apple.security.application-groups group.com.geeksinc.documentexample And in my extensions (in XCode) for each Target: !https://dl.dropboxusercontent.com/u/843217/AppGroupInXCode.png! And it needs to be in the Entitlements.plist for each extension - I missed this the first time. Also, the App Group needs to be setup in the Apple Developer Portal and your Provisioning Profile for your Titanium app must have been generated after the App Group was added to the App Services of the App Id. XCode may do this for you, but better to do it yourself to make sure.
  46. Javier Rayon 2016-05-12

    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!
  47. Eric Wieber 2016-05-16

  48. Eric Wieber 2016-05-18

  49. Eric Merriman 2016-05-23

    Closing as implemented.

JSON Source