- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我已经为我的应用程序添加了一个共享扩展名为 SAMPLE(已存在于应用商店中),名为 lets say SAMPLESHARE。每当用户拍摄照片并尝试分享时,我希望他们通过 Open In 功能的 View Controller ,而不是从 Apple 获得 Post 对话,基本上绕过它。因此,我试图在共享扩展和我的应用程序之间共享图片,方法是创建一个在应用程序和插件之间共享的应用程序组,然后将文件路径传递到我的应用程序的应用程序委托(delegate)的 openURL。
所以在我的主要应用程序委托(delegate)中我有
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [[SAMPLEExternalFileHandler shared] handleExternalFileURL:url];
}
如果我有一个需要打开不同流程的 URL 文件路径,我基本上每次都用它来检查。
在我的 SHAREEXTENSION 中有
#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
我的扩展名 info.plist 是
<?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>
我基本上使用了互联网(知名网站)上的一些公共(public)许可代码,这些代码声称已经通过了应用程序商店的审核流程。
代码中有两种变通方法,一种是从共享扩展中调用 OpenURL(从搜索 SO 看来,如果没有 iOS 8.3 及更高版本的变通方法,这似乎仍然不可能正常进行),第二种是隐藏帖子对话以及当任何人点击共享时苹果默认提供的键盘。这行得通。
我有两个问题
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?
更新:
因此,通过搜索文档,我找到了问题 2 的修复程序,并对其进行了更改。现在一切正常,并且没有 TRUEPREDICATE
,这会在商店中被接受还是有其他方法可以做到这一点?
更新 2:
我现在已经使用 NSUserDefaults
将数据从扩展程序传递到应用程序,我猜这也是共享数据的一个要求。
最佳答案
更新
该应用程序使用 NSUSERDEFAULTS
作为消息传递机制在审核中被接受。这是步骤。
1.) 共享扩展:
#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.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
在您的应用程序委托(delegate)的 openURL 方法中
//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
}
感谢EasyNativeExtensions求指点
关于ios - 在共享扩展和 iOS 应用程序之间共享文件路径/文件的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32228182/
假设我有程序员和艺术家在做一个项目。艺术家有一些他们关心的文件夹: /Doodles /Images/Jpgs 也许程序员有一个这样的文件夹: /Code/View/Jpgs Mercurial 中保
我目前正在开发一个 iOS 应用程序(使用 Swift 3)。为了提高分享的用户体验,我想集成What's App。 事实上,经过一些操作后,用户可以根据需要与 UIActivityViewContr
我想与新的 api 共享图像。 如果我有一个文件的上传表单,我可以与 api 共享该文件,但我试图共享一个本地文件会打破我的头。这是我的尝试: function sharePage(){ const
我在 Azure 门户中设置了一个 iOS 应用来与 OneDrive for Business 集成。 在“对其他应用程序的权限”中,我们选择了所有权限 - Microsoft Graph - Of
所以我让我的应用程序创建一个文件,在本例中它实际上是一个动画 .gif。此动画 .gif 已保存在设备上并已准备就绪 - 我现在要做的是在用户单击“共享”按钮时共享此文件。 简单地说,我怎样才能做到这
我正在为 Android 开发一个应用程序,它使用 Dropbox 来组织文件。我正在探索 Dropbox API,但它的描述和帮助是有限的,因为没有 Dropbox API 的文档。 我仍然希望通过
我的 android 应用程序中有一个文件列表,我希望能够获取选定的项目并通过电子邮件或任何其他共享应用程序发送它们。这是我的代码。 Intent sendIntent = new Intent();
我想知道如何在 Flutter 应用中共享文件? 我看到了一些关于将 Intents 与 mojo 结合使用的旧引用,但似乎不再存在。这似乎是我们应该能够以跨平台方式处理的标准功能(显然 ios 和
如果没有相关文件,我希望从共享位置(绝对路径)提供默认的 robots.txt 文件。 我试过了,但运气不好: location = /robots.txt { expires 30d;
我使用 flutter-darts 创建了 QR码生成应用程序。除了共享部分,其他一切都很好。我使用以下代码共享了我生成的 png图像。 Future _captureAndSharePng() as
我用下面的代码分享一张图片,图片类型是png就可以了。但我很惊讶,如果图像类型是 jpeg,它仍然可以。为什么?谢谢! Intent sharingIntent = new Intent(Intent
我想知道如何使用 drive-sdk 和 python 与用户共享文件。我一直在使用下面的代码,但它不会与指定用户共享文件,也不会产生错误: ... Permission = { 'value':
我正在尝试制作一个应用程序,要求用户选择一个图像文件,然后通过 Intent 将其发送到另一个应用程序(在这种情况下是 Whatsapp,但这应该适用于其他应用程序) 我这样做是为了请求文件: In
我使用来自“react-native”的{Share}。我成功分享了消息,没问题。 现在,我动态生成 PDF 并将其保存在本地。是否可以像共享 URL 一样共享 PDF?我没有找到解决方案。 想了想,
我们有一套应用程序依赖于外部存储上的目录/文件共享。我目前已选择退出 Android 10 操作系统对范围的更改 (requestLegacyExternalStorage),但这即将消失,我花了很多
我使用 TypeScript 通过面向对象编程对我的 javascript 文件进行编码。我想使用 Node 模块 https://npmjs.org/package/typescript-requi
我有一些文件想与任何应用程序共享。我用这个代码 var fileDAta = NSData.FromFile(path); UIActivityViewController activityViewC
我正在运行 docker 容器。在那里运行 arch linux。 在容器内,我有一些文件夹/文件,我想从我的 MAC 访问它们。 我正在使用 samba 共享将容器中的文件共享到我的 MAC。到目前
我曾经写过这样的代码,在使用instruments的时候,发现内存泄露。 NSURL *filePath = [NSURL fileURLWithPath:path];
我一直在关注 Google 的文档以在云端硬盘上共享文件:Share Files 如果我从 Google 云端硬盘界面上传文件到 Google 云端硬盘,然后尝试从我的网络应用程序共享此文件,我会在我
我是一名优秀的程序员,十分优秀!