Dodałem rozszerzenie udziału dla mojej aplikacji, powiedz SAMPLE (już istnieje w sklepie z aplikacjami), nazwijmy powiedzmy SAMPLESHARE. Za każdym razem, gdy użytkownik, powiedzmy, robi zdjęcie i próbuje je udostępnić, chcę, aby przejrzał kontroler widoku funkcji "Otwórz w" i nie uzyskaj dialogu "Poczta" od Apple, zasadniczo go pomijając. Dlatego próbuję udostępnić zdjęcie między rozszerzeniem udziału a moją aplikacją, tworząc grupę aplikacji, która jest udostępniana między aplikacją i wtyczką, a następnie przekazując ścieżki plików do otwartego adresu użytkownika delegata aplikacji z mojej aplikacji.Kod udostępniania ścieżki/pliku pliku między rozszerzeniem udziałów a aplikacją na iOS
Więc moim głównym delegatem aplikacji mam
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [[SAMPLEExternalFileHandler shared] handleExternalFileURL:url];
}
które w zasadzie używać do sprawdzania za każdym razem, gdy mam pliku ścieżkę URL, który musi otworzyć inny przepływ.
W moim SHAREEXTENSION mam
#import "ShareViewController.h"
#import <MobileCoreServices/UTCoreTypes.h>
//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.SAMPLE.SAMPLESHAREPLUGIN";
const NSString * APP_SHARE_URL_SCHEME = @"SAMPLE";
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 ];
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 JPEG
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
A moja Info.plist dla rozszerzenia jest
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>SAMPLESHARE</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.org.SAMPLE.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
</dict>
</plist>
mam w zasadzie stosować jakiś kod Commons License z internetu (podobno miejscu), który twierdzi, przeszedł proces sprawdzania sklepu z aplikacjami.
W kodzie są dwa obejścia, jeden to wywołanie OpenURL z rozszerzenia udziałów (co wydaje się, że od wyszukania SO nie jest normalnie możliwe bez obejścia w systemie iOS 8.3 i nowszych wersjach), a drugie to ukrycie tego wpisu dialog i klawiaturę, którą jabłko zapewnia domyślnie, gdy ktoś kliknie w udział. To działa.
Mam dwa pytania
1.) Will this be accepted on the app store? -- basically how are apps like facebook/whatsapp doing it and they are being accepted?
2.) Whenever I run this, it says `NSExtensionActivationRule` if set to `TRUEPREDICATE` will be rejected in review, what should the value be?
UPDATE:
Więc szorowania poprzez dokumentacji znalazłem poprawkę dla pytania 2 i zmienił to. Teraz wszystko działa, i nie ma żadnego TRUEPREDICATE
, czy zostanie to zaakceptowane w sklepie, czy jest inny sposób na zrobienie tego?
UPDATE 2:
Mam teraz używany NSUserDefaults
przekazać dane z rozszerzenia aplikacji, przypuszczam, że to również jeden wymóg udostępniania danych.
Zaktualizuję go nieco. Tak, został zaakceptowany w recenzji – Slartibartfast
Dzięki za ten pomocny post, spędziłem kilka godzin szukając informacji na ten temat –