20

I tried to delete the storyboard file and related Info.plist entry but this time extension stopped working; it doesn't even launch from XCode.

The operation couldn’t be completed. (LaunchServicesError error 0.)

It is easy on the regular app (containing app) as we see it's entry point and application delegate, but how to do it on extensions too?

frankish
  • 6,738
  • 9
  • 49
  • 100

3 Answers3

47

I did the following steps:

  • Delete the storyboard file from your project
  • Modify the info.plist:

Go to the NSExtension Dictionary, remove this key: NSExtensionMainStoryboard. Replace it with this key NSExtensionPrincipalClass and add your ViewController as the value, e.g. TodayViewController.

before:

<key>NSExtension</key>
<dict>
    <key>NSExtensionMainStoryboard</key>
    <string>MainInterface</string>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.widget-extension</string>
</dict>

after:

<key>NSExtension</key>
<dict>
    <key>NSExtensionPrincipalClass</key>
    <string>TodayViewController</string>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.widget-extension</string>
</dict>
  • If you're using Swift, you have to enable "Embedded Content Contains Swift Code" in the Build Settings of the target. Set it to YES.
  • Additionally I had to add @objc (TodayViewController) in my TodayViewController class (after the imports).

The app should run now. But there were two other things I had to do:

  • Create a view. Obviously there is no view created automatically.

So add these lines:

override func loadView()
{
    view = UIView(frame:CGRect(x:0.0, y:0, width:320.0, height:200.0))
}
  • And set the height of your widget in your viewDidLoad method: self.preferredContentSize = CGSizeMake(0, 200)
Raphael
  • 3,846
  • 1
  • 28
  • 28
  • had to do this to make it work: http://stackoverflow.com/questions/24416003/writing-an-ios-8-share-extension-without-a-storyboard – Cherpak Evgeny Jan 10 '17 at 17:22
  • 1
    May I ask why we have to create a view in the TodayViewController class? Isn't the View Controller already contains a view already? – user6539552 May 10 '17 at 10:26
  • @Raphael, nice answer. I wanted to follow a similar logic for an iMessage extension, but wasn't able to. :-/ – Shyam Jun 28 '17 at 04:13
  • @Raphael, actually I did. Not sure if this is an efficient way. (By adding a childViewController.) But, I guess the crash that resulted in the morning, was to a typo!! :-( – Shyam Jun 28 '17 at 12:22
21

Remove NSExtensionMainStoryboard from Info.plist Add NSExtensionPrincipalClass = YourViewController

Don't forget to create your own view in loadView

frankish
  • 6,738
  • 9
  • 49
  • 100
  • 2
    Note: This needs to be under the NSExtension dictionary in the info.plist for the extension. – xtravar Dec 21 '14 at 05:41
  • 1
    had to do this to make it work: http://stackoverflow.com/questions/24416003/writing-an-ios-8-share-extension-without-a-storyboard – Cherpak Evgeny Jan 10 '17 at 17:22
  • 1
    Yeah this post works, you have to insert `@objc(PrincipalClassName)` before your main class declaration – Bejil Jul 04 '19 at 13:03
8

FWIW, it didn't work for me until I added a prefix of the module name for my Swift view controller class, e.g.

<key>NSExtension</key>
<dict>
    <!-- ... -->
    <key>NSExtensionPrincipalClass</key>
    <string>SafariActionExtension.RootViewController</string>
    <!-- ... -->
</dict>

That is probably because class lookup for Swift modules turns module names into prefix for class name. E.g. to create your class in code you would write NSStringFromClass("SafariActionExtension.RootViewController"), hence the prefix.

Sash Zats
  • 5,376
  • 2
  • 28
  • 42
  • 1
    I couldn't get it working with the prefix, so I just used the @obj(RootViewController) to specify the class name and it works. – Tapani Sep 21 '16 at 12:20
  • This answer solved my problem! :-) Should be marked as right answer! – Alexey Oct 31 '16 at 09:17