tweag / ignite-action-extension-example

Example of writing action extensions with in a React Native app using Ignite
4 stars 1 forks source link

Hint for adding self.extensionContext.inputItems? #5

Open swyxio opened 7 years ago

swyxio commented 7 years ago

Thanks so much for the fantastic blogpost, I managed to follow it through and get it running!!!

As you hint at the end of the blogpost, information needs to be passed in order to make the extension useful. As someone who doesn't know obj C this can be a bit much but my initial attempt was this:

- (void)loadView {
  NSURL *jsCodeLocation;

  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
  NSExtensionItem *input = self.extensionContext.inputItems.firstObject;
  NSDictionary *initialProps = [NSDictionary dictionaryWithObjects:@[[NSNumber numberWithBool: TRUE], input] forKeys:@[@"isActionExtension",@"key2"]];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"ActionExtensionExample4"
                                               initialProperties:initialProps
                                                   launchOptions:nil];
  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
  self.view = rootView;
  actionViewController = self;
}

however this input and other variants i tried don't seem to work. any quick tips here? just want to get to a point where i can pass the shared data from objC into react Native and then i can run with it from there. I'm so close!!

swyxio commented 7 years ago

after spending a few hours reading up i think its misleading to talk about self.extensionContext.inputItems. that seems to be for getting data OUT of the extension into the other app, whereas the normal use case is for getting data FROM the other app INTO the extension. what seems to work is running a javascript snippet under NSExtensionJavaScriptPreprocessingFile in info.plist and then some how retrieving that info in NSExtensionJavaScriptPreprocessingResultsKey. however all the tutorials i've found are written in swift (like this one) so maybe that would be a really good addendum to your post as nobody seems to write Obj C content anymore (except RN! lol)

regardless.. still appreciate what you did here even though I ultimately wound up not being able to use it. I really need to learn objC/swift.

swyxio commented 7 years ago

For people of the future: i wrote up my current status here: https://www.reddit.com/r/reactnative/comments/71nr4q/has_anyone_had_experience_building_ios_share/dngieug/

alexgurr commented 6 years ago

Did you get anywhere with this in the end? I can't seem to make it work either...

swyxio commented 6 years ago

nope

alexgurr commented 6 years ago

Don't know if you are still interested? I actually got this working.

  NSURL *jsCodeLocation;

  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];

  NSExtensionItem *item = self.extensionContext.inputItems.firstObject;
  NSItemProvider *itemProvider = item.attachments.firstObject;

  [itemProvider loadItemForTypeIdentifier:@"public.url" options:nil completionHandler:^(NSURL *url, NSError *error) {
    dispatch_async(dispatch_get_main_queue(), ^{
      NSDictionary *initialProps = @{@"isActionExtension": @YES, @"args": url.absoluteString};

      RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                          moduleName:@"mobileapp"
                                                   initialProperties:initialProps
                                                       launchOptions:nil];

      rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

      self.view = rootView;

      actionViewController = self;
    });
  }];

The reason your code doesn't work is because to get the data out of a NSItemProvider object, you have to do an async call, which is what the completionHandler is doing. It's a callback when the data has been pulled out.

The dispatch_async function is for UI changes on the main thread. Without it, constructing the root view would throw.

I'm passing the URL down as the 'args' prop. Hope this helps!

tokict commented 5 years ago

For anyone dropping here, if you create an app extension from xcode template and set it not to have an interface, it will automaticaly be created with an example on how to access safari content, run js and change content of the site