Code to share file path/file between a share extension and iOS app

后端 未结 3 1729
心在旅途
心在旅途 2021-01-04 02:18

I have added a share extension for my app say SAMPLE (already exists on the app store), called lets say SAMPLESHARE. Whenever a user, say takes a picture and tries to share

3条回答
  •  一生所求
    2021-01-04 02:47

    UPDATE

    The app was accepted in the review using NSUSERDEFAULTS as the message passing mechanism. Here are the steps.

    1.) Share extension:

    #import "ShareViewController.h"
    #import 
    //Macro to hide post dialog or not, if defined, will be hidden, comment during debugging
    #define HIDE_POST_DIALOG
    
    @interface ShareViewController ()
    
    @end
    
    @implementation ShareViewController
    
    NSUInteger m_inputItemCount = 0; // Keeps track of the number of attachments we have opened asynchronously.
    NSString * m_invokeArgs = NULL;  // A string to be passed to your AIR app with information about the attachments.
    NSString * APP_SHARE_GROUP = @"group.com.schemename.nameofyourshareappgroup";
    const NSString * APP_SHARE_URL_SCHEME = @"schemename";
    CGFloat m_oldAlpha = 1.0; // Keeps the original transparency of the Post dialog for when we want to hide it.
    
    - (BOOL)isContentValid {
        // Do validation of contentText and/or NSExtensionContext attachments here
        return YES;
    }
    
    - ( void ) didSelectPost
    {
    #ifdef HIDE_POST_DIALOG
        return;
    #endif
    
        [ self passSelectedItemsToApp ];
        // Note: This call is expected to be made here. Ignore it. We'll tell the host we are done after we've invoked the app.
        //    [ self.extensionContext completeRequestReturningItems: @[] completionHandler: nil ];
    }
    - ( void ) addImagePathToArgumentList: ( NSString * ) imagePath
    {
        assert( NULL != imagePath );
    
        // The list of arguments we will pass to the AIR app when we invoke it.
        // It will be a comma-separated list of file paths: /path/to/image1.jpg,/path/to/image2.jpg
        if ( NULL == m_invokeArgs )
        {
            m_invokeArgs = imagePath;
        }
        else
        {
            m_invokeArgs = [ NSString stringWithFormat: @"%@,%@", m_invokeArgs, imagePath ];
        }
    }
    
    - ( NSString * ) saveImageToAppGroupFolder: ( UIImage * ) image
                                    imageIndex: ( int ) imageIndex
    {
        assert( NULL != image );
    
        NSData * jpegData = UIImageJPEGRepresentation( image, 1.0 );
    
        NSURL * containerURL = [ [ NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier: APP_SHARE_GROUP ];
        NSString * documentsPath = containerURL.path;
    
        // Note that we aren't using massively unique names for the files in this example:
        NSString * fileName = [ NSString stringWithFormat: @"image%d.jpg", imageIndex ];
    
        NSString * filePath = [ documentsPath stringByAppendingPathComponent: fileName ];
        [ jpegData writeToFile: filePath atomically: YES ];
    
        //Mahantesh -- Store image url to NSUserDefaults
    
        NSUserDefaults *defaults=[[NSUserDefaults alloc] initWithSuiteName:@"group.com.schemename.nameofyourshareappgroup"];
        [defaults setObject:filePath forKey:@"url"];
        [defaults synchronize];
    
        return filePath;
    }
    
    - ( void ) passSelectedItemsToApp
    {
        NSExtensionItem * item = self.extensionContext.inputItems.firstObject;
    
        // Reset the counter and the argument list for invoking the app:
        m_invokeArgs = NULL;
        m_inputItemCount = item.attachments.count;
    
        // Iterate through the attached files
        for ( NSItemProvider * itemProvider in item.attachments )
        {
            // Check if we are sharing a Image
            if ( [ itemProvider hasItemConformingToTypeIdentifier: ( NSString * ) kUTTypeImage ] )
            {
                // Load it, so we can get the path to it
                [ itemProvider loadItemForTypeIdentifier: ( NSString * ) kUTTypeImage
                                                 options: NULL
                                       completionHandler: ^ ( UIImage * image, NSError * error )
                 {
                     static int itemIdx = 0;
    
                     if ( NULL != error )
                     {
                         NSLog( @"There was an error retrieving the attachments: %@", error );
                         return;
                     }
    
                     // The app won't be able to access the images by path directly in the Camera Roll folder,
                     // so we temporary copy them to a folder which both the extension and the app can access:
                     NSString * filePath = [ self saveImageToAppGroupFolder: image imageIndex: itemIdx ];
    
                     // Now add the path to the list of arguments we'll pass to the app:
                     [ self addImagePathToArgumentList: filePath ];
    
                     // If we have reached the last attachment, it's time to hand control to the app:
                     if ( ++itemIdx >= m_inputItemCount )
                     {
                         [ self invokeApp: m_invokeArgs ];
                     }
                 } ];
            }
        }
    }
    - ( void ) invokeApp: ( NSString * ) invokeArgs
    {
        // Prepare the URL request
        // this will use the custom url scheme of your app
        // and the paths to the photos you want to share:
        NSString * urlString = [ NSString stringWithFormat: @"%@://%@", APP_SHARE_URL_SCHEME, ( NULL == invokeArgs ? @"" : invokeArgs ) ];
        NSURL * url = [ NSURL URLWithString: urlString ];
    
        NSString *className = @"UIApplication";
        if ( NSClassFromString( className ) )
        {
            id object = [ NSClassFromString( className ) performSelector: @selector( sharedApplication ) ];
            [ object performSelector: @selector( openURL: ) withObject: url ];
        }
    
        // Now let the host app know we are done, so that it unblocks its UI:
        [ super didSelectPost ];
    }
    
    #ifdef HIDE_POST_DIALOG
    - ( NSArray * ) configurationItems
    {
        // Comment out this whole function if you want the Post dialog to show.
        [ self passSelectedItemsToApp ];
    
        // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
        return @[];
    }
    #endif
    
    
    #ifdef HIDE_POST_DIALOG
    - ( void ) willMoveToParentViewController: ( UIViewController * ) parent
    {
        // This is called at the point where the Post dialog is about to be shown.
        // Make it transparent, so we don't see it, but first remember how transparent it was originally:
    
        m_oldAlpha = [ self.view alpha ];
        [ self.view setAlpha: 0.0 ];
    }
    #endif
    
    #ifdef HIDE_POST_DIALOG
    - ( void ) didMoveToParentViewController: ( UIViewController * ) parent
    {
        // Restore the original transparency:
        [ self.view setAlpha: m_oldAlpha ];
    }
    #endif
    #ifdef HIDE_POST_DIALOG
    - ( id ) init
    {
        if ( self = [ super init ] )
        {
            // Subscribe to the notification which will tell us when the keyboard is about to pop up:
            [ [ NSNotificationCenter defaultCenter ] addObserver: self selector: @selector( keyboardWillShow: ) name: UIKeyboardWillShowNotification    object: nil ];
        }
    
        return self;
    }
    #endif
    #ifdef HIDE_POST_DIALOG
    - ( void ) keyboardWillShow: ( NSNotification * ) note
    {
        // Dismiss the keyboard before it has had a chance to show up:
        [ self.view endEditing: true ];
    }
    #endif
    @end
    
    1. In the openURL method of your application delegate

              //Slartibartfast -- For the case where we are opening app from an extension
               NSString *STATIC_FILE_HANDLE = @"file://";
              //If app is opened from share extension, do the following
              /*
               1.) Get path of shared file from NSUserDefaults
               2.) Get data from file and store in some variable
               3.) Create a new accesible unique file path
               4.) Dump data created into this file.
               */
      
              NSUserDefaults *defaults=[[NSUserDefaults alloc] initWithSuiteName:YOURAPP_STATIC_APP_GROUP_NAME];
              NSString *path=nil;
              if(defaults)
              {
                  [defaults synchronize];
                  path = [defaults stringForKey:@"url"];
              }
      
              if(path.length != 0)
              {
                  NSData *data;
                  //Get file path from url shared
                  NSString * newFilePathConverted = [STATIC_FILE_HANDLE stringByAppendingString:path];
                  url = [ NSURL URLWithString: newFilePathConverted ];
                  data = [NSData dataWithContentsOfURL:url];
                  //Create a regular access path because this app cant preview a shared app group path
                  NSString *regularAccessPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
                  NSString *uuid = [[NSUUID UUID] UUIDString];
                  //Copy file to a jpg image(ignore extension, will convert from png)
                  NSString *uniqueFilePath= [ NSString stringWithFormat: @"/image%@.jpg", uuid];
                  regularAccessPath = [regularAccessPath stringByAppendingString:uniqueFilePath];
                  NSString * newFilePathConverted1 = [STATIC_FILE_HANDLE stringByAppendingString:regularAccessPath];
                  url = [ NSURL URLWithString: newFilePathConverted1 ];
                  //Dump existing shared file path data into newly created file.
                  [data writeToURL:url atomically:YES];
                  //Reset NSUserDefaults to Nil once file is copied.
                  [defaults setObject:nil forKey:@"url"];
      
              }
          //Do what you want
          }
      

    Thanks to EasyNativeExtensions for pointers

提交回复
热议问题