I have code to show a document as follows:
documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:self.thisUrl];
NSString *pathExtension = [self.thisUrl pathExtension];
if (pathExtension) {
NSString *UTI = (__bridge NSString*)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)(pathExtension), NULL);
if (UTI) {
documentInteractionController.UTI = UTI;
}
}
documentInteractionController.delegate = self;
[documentInteractionController presentOptionsMenuFromBarButtonItem:shareButton animated:YES];
When the options menu is displayed, it shows a list of apps that can open the document (e.g. Message), along with a list of actions below.
The options menu shows a list actions that is different from the menu shown in e.g., the Mail app.
The main difference is that the Mail app shows a "print" option, while my options menu does not. How do I get the options menu to show the print option?
EDIT:
I did a further test where I implemented the methods:
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller canPerformAction:(SEL)action
{
return YES;
}
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller performAction:(SEL)action
{
return YES; // or NO, doesn't matter
}
This had the effect of showing the "print", "copy" and "save to camera roll" actions in the popup view. Nothing happened when I tapped them, probably because I didn't properly implement -performAction. I also get a warning in the console log about using legacy methods.
This was a step backwards in some ways because I could no longer print some documents which were able to print correctly with the document interaction controller before I added those methods.
Apple encourage you to use UIActivityViewController. You can easily achieve this with that. However Print option is available only if your sharing content type supports printing. You can see a list of supported activities by data types here
- (IBAction)shareButton:(UIBarButtonItem *)sender
{
NSString *textToShare = #"Text to share";
NSURL *myWebContent = [NSURL URLWithString:#"http://yourpath.com/yourfile.pdf"]; // set your printable file here!
NSData *myData = [NSData dataWithContentsOfURL:myWebContent];
NSArray *objectsToShare = #[textToShare, myData];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil];
//Add exclusions here
NSArray *excludeActivities = #[UIActivityTypeAirDrop,
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToFlickr,
UIActivityTypePostToVimeo];
activityVC.excludedActivityTypes = excludeActivities;
[self presentViewController:activityVC animated:YES completion:nil];
}
I got this working using the QuickLook framework. I don't know why the "print" option sometimes doesn't appear for the document interaction controller, but then again, apparantly noone else does either.
The QuickLook framework supports previewing some document types but not all, so I left in my previous view controller and the document interaction controller for those unsupported types.
Below is a snippet of my working code.
#interface PreviewItemDataSource ()
#property (nonatomic, retain) NSURL* item;
#end
#implementation PreviewItemDataSource
#synthesize item=_item;
+(PreviewItemDataSource*)dataSourceWithItem:(NSURL*)item
{
PreviewItemDataSource *source = [[PreviewItemDataSource alloc] init];
source.item = item;
return source;
}
-(NSInteger) numberOfPreviewItemsInPreviewController:(QLPreviewController*)controller {
return 1;
}
- (id<QLPreviewItem>) previewController:(QLPreviewController*)controller previewItemAtIndex:(NSInteger)index {
return self.item;
}
#end
#interface AppDelegate ()
#property (nonatomic, retain) PreviewItemDataSource *dataSource;
#end
...
-(void) openExternalFile:(NSString*) filePath withDelegate:(id<ChildBrowserDelegate>)delegate
{
if ([filePath length] == 0)
return;
NSURL *item = [NSURL URLWithString:filePath];
if (item && [QLPreviewController canPreviewItem:item]) {
[self openQuickLookForItem:item];
} else {
// previous method unchanged
}
}
- (void) openQuickLookForItem:(NSURL*)item {
QLPreviewController *controller = [[QLPreviewController alloc] init];
PreviewItemDataSource *dataSource = [PreviewItemDataSource dataSourceWithItem:item];
controller.dataSource = dataSource;
controller.modalPresentationStyle = UIModalPresentationFullScreen;
[controller setCurrentPreviewItemIndex:0];
[self.viewController presentViewController:controller animated:YES completion:nil];
self.dataSource = dataSource;
}
Related
edit: I finally solved this, it was a combination of a caching problem and a missing line of code. I never actually added the task to the view controller, somehow I missed that step. But also I had strange errors just running the github demo project and had to reboot and sudo delete the cache directory in order to get Xcode to function as it should.
I am trying to implement Research Kit in Objective-C. There are no tutorials and very little documentation to turn to. I am getting a crash "Visual consent step has no visible scenes". I have one view controller and on that view controller I have a button that triggers the IBAction "consentTapped". I have attempted to adapt the Ray Wenderlich tutorial http://www.raywenderlich.com/104575/researchkit-tutorial-with-swift and this GitHub project: https://github.com/weberbry/ResearchKitConsentDemo
In an attempt to troubleshoot this myself I have put all the code in viewDidAppear, taking it out of encapsulated methods because I thought I made a mistake that way but there is still a problem:
Here is my code:
#import "ViewController.h"
#import <ResearchKit/ResearchKit.h>
#interface ViewController ()<ORKTaskViewControllerDelegate>
#property (strong, nonatomic) ORKConsentDocument *consentDocument;
#property (strong, nonatomic) ORKOrderedTask *orderedTask;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSString *resource = [[NSBundle mainBundle] pathForResource:#"ConsentText" ofType:#"json"];
NSData *consentData = [NSData dataWithContentsOfFile:resource];
NSDictionary *parsedConsentData = [NSJSONSerialization JSONObjectWithData:consentData options:NSJSONReadingMutableContainers error:nil];
NSArray *sectionDataParsedFromInputFile = [parsedConsentData objectForKey:#"sections"];
NSMutableArray *consentSections = [NSMutableArray new];
for (NSDictionary *sectionDictionary in sectionDataParsedFromInputFile) {
ORKConsentSectionType sectionType = [[sectionDictionary objectForKey:#"sectionType"] integerValue];
NSString *title = [sectionDictionary objectForKey:#"sectionTitle"];
NSString *summary = [sectionDictionary objectForKey:#"sectionSummary"];
NSString *detail = [sectionDictionary objectForKey:#"sectionDetail"];
ORKConsentSection *section = [[ORKConsentSection alloc] initWithType:sectionType];
section.title = title;
section.summary = summary;
section.htmlContent = detail;
ORKConsentSection *consentSection = section;
[consentSections addObject:consentSection];
}
ORKConsentSection *introSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
introSection.title = #"Intro Language";
introSection.content = #"This will only be shown in the consent document because this sectionType is map to ORKConsentSectionTypeOnlyInDocument. A consent document can include many sections with type ORKConsentSectionTypeOnlyInDocument. In this document there is a ORKConsentSectionTypeOnlyInDocument section as an intro and one as a closing section";
[consentSections insertObject:introSection atIndex:0];
ORKConsentSection *closingSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
closingSection.title = #"Additional Terms";
closingSection.htmlContent = #"Adding a ORKConsentSectionTypeOnlyInDocument at the end of a consent can be helpful to include any additional legal or related information.";
[consentSections addObject:closingSection];
self.consentDocument = [ORKConsentDocument new];
self.consentDocument.title = #"Demo Consent";
self.consentDocument.sections = consentSections;
ORKConsentSignature *signature = [ORKConsentSignature new];
self.consentDocument.signatures = [NSArray arrayWithObject:signature];
ORKVisualConsentStep *visualConsentStep = [[ORKVisualConsentStep alloc] initWithIdentifier:#"visualConsentStep" document:self.consentDocument];
ORKConsentReviewStep *consentReviewStep = [[ORKConsentReviewStep alloc] initWithIdentifier:#"consentReviewStep" signature:self.consentDocument.signatures.firstObject inDocument:self.consentDocument];
consentReviewStep.text = #"Review Consent!";
consentReviewStep.reasonForConsent = #"I confirm that I consent to join this study";
self.orderedTask = [[ORKOrderedTask alloc] initWithIdentifier:#"consent" steps:#[visualConsentStep, consentReviewStep]];
}
- (IBAction)consentTapped:(id)sender {
ORKTaskViewController *taskViewController = [[ORKTaskViewController alloc]initWithTask:self.orderedTask taskRunUUID:nil];
taskViewController.delegate = self;
[self presentViewController:taskViewController animated:YES completion:nil];
}
- (void)taskViewController:(ORKTaskViewController *)taskViewController
didFinishWithReason:(ORKTaskViewControllerFinishReason)reason
error:(NSError *)error {
ORKTaskResult *taskResult = [taskViewController result];
[self dismissViewControllerAnimated:YES completion:nil];
}
Due to the wording of the error I feel like there should be another view controller scene but I didn't see one on the Ray Wenderlich tutorial unless I missed it. I don't know swift at all yet so if you do and you see that I missed something please let me know.
The crash happens as you leave viewDidAppear.
Also this is my very first post here so if I have not followed community guidelines please let me know and I will modify my post at once.
edit: here is the working code. And remember, sudo delete your DerivedData folder, and reboot if you have strange errors in addition to the original error I posted. The missing line was "taskViewController.task = self.orderedTask;"
#import "ViewController.h"
#import <ResearchKit/ResearchKit.h>
#interface ViewController ()<ORKTaskViewControllerDelegate>
#property (strong, nonatomic) ORKConsentDocument *consentDocument;
#property (strong, nonatomic) ORKOrderedTask *orderedTask;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSString *resource = [[NSBundle mainBundle] pathForResource:#"ConsentText" ofType:#"json"];
NSData *consentData = [NSData dataWithContentsOfFile:resource];
NSDictionary *parsedConsentData = [NSJSONSerialization JSONObjectWithData:consentData options:NSJSONReadingMutableContainers error:nil];
NSArray *sectionDataParsedFromInputFile = [parsedConsentData objectForKey:#"sections"];
NSMutableArray *consentSections = [NSMutableArray new];
for (NSDictionary *sectionDictionary in sectionDataParsedFromInputFile) {
ORKConsentSectionType sectionType = [[sectionDictionary objectForKey:#"sectionType"] integerValue];
NSString *title = [sectionDictionary objectForKey:#"sectionTitle"];
NSString *summary = [sectionDictionary objectForKey:#"sectionSummary"];
NSString *detail = [sectionDictionary objectForKey:#"sectionDetail"];
ORKConsentSection *section = [[ORKConsentSection alloc] initWithType:sectionType];
section.title = title;
section.summary = summary;
section.htmlContent = detail;
ORKConsentSection *consentSection = section;
[consentSections addObject:consentSection];
}
ORKConsentSection *introSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
introSection.title = #"Intro Language";
introSection.htmlContent = #"This will only be shown in the consent document because this sectionType is map to ORKConsentSectionTypeOnlyInDocument. A consent document can include many sections with type ORKConsentSectionTypeOnlyInDocument. In this document there is a ORKConsentSectionTypeOnlyInDocument section as an intro and one as a closing section";
[consentSections insertObject:introSection atIndex:0];
ORKConsentSection *closingSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
closingSection.title = #"Additional Terms";
closingSection.htmlContent = #"Adding a ORKConsentSectionTypeOnlyInDocument at the end of a consent can be helpful to include any additional legal or related information.";
[consentSections addObject:closingSection];
NSArray *sections = consentSections;
self.consentDocument = [ORKConsentDocument new];
self.consentDocument.title = #"Demo Consent";
self.consentDocument.sections = consentSections;
ORKConsentSignature *signature = [ORKConsentSignature new];
self.consentDocument.signatures = [NSArray arrayWithObject:signature];
ORKVisualConsentStep *visualConsentStep = [[ORKVisualConsentStep alloc] initWithIdentifier:#"visualConsentStep" document:self.consentDocument];
ORKConsentReviewStep *consentReviewStep = [[ORKConsentReviewStep alloc] initWithIdentifier:#"consentReviewStep" signature:self.consentDocument.signatures.firstObject inDocument:self.consentDocument];
consentReviewStep.text = #"Review Consent!";
consentReviewStep.reasonForConsent = #"I confirm that I consent to join this study";
self.orderedTask = [[ORKOrderedTask alloc] initWithIdentifier:#"consent" steps:#[visualConsentStep, consentReviewStep]];
}
- (IBAction)consentTapped:(id)sender {
ORKTaskViewController *taskViewController = [[ORKTaskViewController alloc] init];
taskViewController.task = self.orderedTask;
taskViewController.delegate = self;
[self presentViewController:taskViewController animated:YES completion:nil];
}
- (void)taskViewController:(ORKTaskViewController *)taskViewController
didFinishWithReason:(ORKTaskViewControllerFinishReason)reason
error:(NSError *)error {
ORKTaskResult *taskResult = [taskViewController result];
[self dismissViewControllerAnimated:YES completion:nil];
}
Answer by Abbey Jackson:
Here is the working code. And remember, sudo delete your DerivedData folder, and reboot if you have strange errors in addition to the original error I posted. The missing line was taskViewController.task = self.orderedTask;
#import "ViewController.h"
#import <ResearchKit/ResearchKit.h>
#interface ViewController ()<ORKTaskViewControllerDelegate>
#property (strong, nonatomic) ORKConsentDocument *consentDocument;
#property (strong, nonatomic) ORKOrderedTask *orderedTask;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSString *resource = [[NSBundle mainBundle] pathForResource:#"ConsentText" ofType:#"json"];
NSData *consentData = [NSData dataWithContentsOfFile:resource];
NSDictionary *parsedConsentData = [NSJSONSerialization JSONObjectWithData:consentData options:NSJSONReadingMutableContainers error:nil];
NSArray *sectionDataParsedFromInputFile = [parsedConsentData objectForKey:#"sections"];
NSMutableArray *consentSections = [NSMutableArray new];
for (NSDictionary *sectionDictionary in sectionDataParsedFromInputFile) {
ORKConsentSectionType sectionType = [[sectionDictionary objectForKey:#"sectionType"] integerValue];
NSString *title = [sectionDictionary objectForKey:#"sectionTitle"];
NSString *summary = [sectionDictionary objectForKey:#"sectionSummary"];
NSString *detail = [sectionDictionary objectForKey:#"sectionDetail"];
ORKConsentSection *section = [[ORKConsentSection alloc] initWithType:sectionType];
section.title = title;
section.summary = summary;
section.htmlContent = detail;
ORKConsentSection *consentSection = section;
[consentSections addObject:consentSection];
}
ORKConsentSection *introSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
introSection.title = #"Intro Language";
introSection.htmlContent = #"This will only be shown in the consent document because this sectionType is map to ORKConsentSectionTypeOnlyInDocument. A consent document can include many sections with type ORKConsentSectionTypeOnlyInDocument. In this document there is a ORKConsentSectionTypeOnlyInDocument section as an intro and one as a closing section";
[consentSections insertObject:introSection atIndex:0];
ORKConsentSection *closingSection = [[ORKConsentSection alloc] initWithType:ORKConsentSectionTypeOnlyInDocument];
closingSection.title = #"Additional Terms";
closingSection.htmlContent = #"Adding a ORKConsentSectionTypeOnlyInDocument at the end of a consent can be helpful to include any additional legal or related information.";
[consentSections addObject:closingSection];
NSArray *sections = consentSections;
self.consentDocument = [ORKConsentDocument new];
self.consentDocument.title = #"Demo Consent";
self.consentDocument.sections = consentSections;
ORKConsentSignature *signature = [ORKConsentSignature new];
self.consentDocument.signatures = [NSArray arrayWithObject:signature];
ORKVisualConsentStep *visualConsentStep = [[ORKVisualConsentStep alloc] initWithIdentifier:#"visualConsentStep" document:self.consentDocument];
ORKConsentReviewStep *consentReviewStep = [[ORKConsentReviewStep alloc] initWithIdentifier:#"consentReviewStep" signature:self.consentDocument.signatures.firstObject inDocument:self.consentDocument];
consentReviewStep.text = #"Review Consent!";
consentReviewStep.reasonForConsent = #"I confirm that I consent to join this study";
self.orderedTask = [[ORKOrderedTask alloc] initWithIdentifier:#"consent" steps:#[visualConsentStep, consentReviewStep]];
}
- (IBAction)consentTapped:(id)sender {
ORKTaskViewController *taskViewController = [[ORKTaskViewController alloc] init];
taskViewController.task = self.orderedTask;
taskViewController.delegate = self;
[self presentViewController:taskViewController animated:YES completion:nil];
}
- (void)taskViewController:(ORKTaskViewController *)taskViewController
didFinishWithReason:(ORKTaskViewControllerFinishReason)reason
error:(NSError *)error {
ORKTaskResult *taskResult = [taskViewController result];
[self dismissViewControllerAnimated:YES completion:nil];
}
I am using the following code to set up UIActivityViewController:
NSArray *activityItems = [NSArray arrayWithObjects:[self textMessageToShare], nil];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
[activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed) {
if (completed) {
[self sendFeedbackWithIndexPath:indexPath AndLikeType:100 AndCell:nil];
}
}];
[self.navigationController presentViewController:activityViewController
animated:YES
completion:^{
// ...
}];
Issue is that when I copy a message or post to facebook or twitter or email or gmail app or to default Messages app, the new line characters that are in [self textMessageToShare] are maintained. However, if I share to other activities like WhatsApp or Viber - all the new line characters are removed, and the whole message is sent as one single line.
Whereas, if I share just text through iOS default Notes app, new line characters are maintained when shared to these apps. How would the Notes app be storing the new line characters? I am using \n as the new line character.
For my life unable to even find the reason. Can anyone help?
I was able to make it work by converting the newline characters to "<br/>":
_myDataString= self.textview.text;
_myDataString= [_myDataString stringByReplacingOccurrencesOfString:#"\n" withString:#"<br/>"];
Please check the new line issue in whats app share using uiactivityviewcontroller.
#import <UIKit/UIKit.h>
#interface ShareActivity : UIActivityItemProvider
#property (nonatomic, strong) NSString *message;
#property (nonatomic, strong) NSArray *activities;
#end
#import "ShareActivity.h"
#implementation ShareActivity
#synthesize message = _message;
#synthesize activities = _activities;
- (id) activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
if([activityType isEqualToString:#"net.whatsapp.WhatsApp.ShareExtension"])
{
return [self.message stringByReplacingOccurrencesOfString:#"\n" withString:#"<br/>"];
}
else if ([self.activities containsObject:activityType])
{
return [self.message stringByReplacingOccurrencesOfString:#"\n" withString:#"<br/>"];
}
else
{
return self.message;
}
return nil;
}
- (id) activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
return #"";
}
In View Controller Class on any action button to pop up the share view
Apply this action on any button action
-(void)shareAction
{
ShareActivity *shareObj = [[ShareActivity alloc] initWithPlaceholderItem:#""];
NSString *message = #"New\nLine\nText\nMessage";
[shareObj setMessage:message];
NSArray* dataToShare = #[shareObj];
NSArray *excludeActivities = #[UIActivityTypePrint,UIActivityTypeOpenInIBooks,UIActivityTypeAddToReadingList,UIActivityTypePostToTencentWeibo,UIActivityTypeSaveToCameraRoll,UIActivityTypeAirDrop];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
activityVC.excludedActivityTypes = excludeActivities;
[activityVC setCompletionHandler:^(NSString *act, BOOL done)
{
NSString *ServiceMsg = nil;
if ( [act isEqualToString:UIActivityTypeMail] )
{
ServiceMsg = #"Mail sent!";
}
else if ( [act isEqualToString:UIActivityTypePostToTwitter] )
{
ServiceMsg = #"Post on twitter, ok!";
}
else if ( [act isEqualToString:UIActivityTypePostToFacebook] )
{
ServiceMsg = #"Post on facebook, ok!";
}
else if ( [act isEqualToString:UIActivityTypeCopyToPasteboard] )
{
ServiceMsg = #"Message copy to pasteboard";
}
else if ( [act isEqualToString:UIActivityTypePostToFlickr] )
{
ServiceMsg = #"Message sent to flickr";
}
else if ( [act isEqualToString:UIActivityTypePostToVimeo] )
{
ServiceMsg = #"Message sent to Vimeo";
}
else
{
}
}];
[self presentViewController:activityVC animated:YES completion:nil];
}
hi its me again i was looking for the right answer
and i found that you can do it by using a Custom Share Message to Different Providers .
and you can find an example from this Code check for MyActivityItemProvider class .
https://github.com/apascual/flip-your-phone
i hove a problem posting the code here so i think the link above will help
Thanks to MuslimDev2015 I have been able to develop a solution:
https://github.com/lorenzoPrimi/NewlineActivityItemProvider
Try it and let me know.
You can send the text as multiple items each item is just one line.
let lines = text.components(separatedBy: "\n")
let activityViewController = UIActivityViewController(activityItems: lines, applicationActivities: nil)
How do i share image from imageView. Here is my code for imageView:
UIImage *myImage = [UIImage imageNamed:[NSString stringWithFormat:
#"image%d.jpg", i]];
UIImageView *myImageView = [[UIImageView alloc] initWithImage:myImage];
[myImageView setFrame:CGRectMake(xOrigin, 0,
self.view.frame.size.width,
self.view.frame.size.height)];
_postImage.image = myImage;
}
- (IBAction)shareButtonPressed:(id)sender {
NSArray *activityItems;
if (_postImage.image != nil) {
activityItems = #[_postImage.image];
}
UIActivityViewController *activityVC = [[UIActivityViewController alloc]
initWithActivityItems:activityItems
applicationActivities:nil];
[self presentViewController:activityVC animated:YES completion:nil];
}
I get error - No share action available.Thanks in advance.
You probably forgot to initialize _postImage. Try to replace:
_postImage.image = myImage;
with:
_postImage = [[UIImageView alloc] initWithImage:myImage];
To get your image on activityViewController you need to create your custom Activity with that image which you want to show. Following are step's to create and show your custom activity with your image.
1.Create a new file subclassing UIActivity namely, "CustomActivity". Then in the CustomActivity.m file you need to write down following method.
- (NSString *)activityType {
return #"yourappname.Review.App"; //type
}
- (NSString *)activityTitle {
return #"Review App"; //title for activity
}
- (UIImage *)activityImage {
return [UIImage imageNamed:#"Icon.png"]; //image
}
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
NSLog(#"%s", __FUNCTION__);
return YES;
}
- (void)prepareWithActivityItems:(NSArray *)activityItems {
NSLog(#"%s",__FUNCTION__);
}
- (UIViewController *)activityViewController {
NSLog(#"%s",__FUNCTION__);
return nil;
}
- (void)performActivity {
//What your cust activity woudl perform when user tap onto it.
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://www.apple.com/"]];
[self activityDidFinish:YES];
}
Then in your mainVC you could import this class and add below lines to use this custom activity.
NSString *textItem = #"provide your string";
UIImage *imageToShare = [UIImage imageNamed:#"Icon.png"]; //Provide your activity image
NSArray *items = [NSArray arrayWithObjects:textItem,imageToShare,nil];
custAct = [[CustomActivity alloc]init];
UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:#[custAct]];
[self presentViewController:controller animated:YES completion:nil];
Now you would be able to see your image with activity that you want to perform.
If my understanding is wrong, do correct me.
In my project I'm using WSAssetPickerController.
Despite the toolbar not working (not a huge issue), everything is working fine.
I have added a share button in the view controller, but I can't seem to get the UIDocumentInteractionController to get called, I tried copying the same method I'm using for files saved in the apps folder (which works fine). But here it's not.
How the irrelevant Downloads page works:
NSString *fileName = [directoryContents objectAtIndex:indexPath.row];
NSString *path;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Downloads"];
path = [path stringByAppendingPathComponent:fileName];
documentController = [[UIDocumentInteractionController alloc] init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
[documentController setDelegate:self];
[documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
How the images get loaded:
#pragma mark - Fetching Code
- (void)fetchAssets
{
// TODO: Listen to ALAssetsLibrary changes in order to update the library if it changes.
// (e.g. if user closes, opens Photos and deletes/takes a photo, we'll get out of range/other error when they come back.
// IDEA: Perhaps the best solution, since this is a modal controller, is to close the modal controller.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (!result || index == NSNotFound) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
self.navigationItem.title = [NSString stringWithFormat:#"%#", [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName]];
});
return;
}
WSAssetWrapper *assetWrapper = [[WSAssetWrapper alloc] initWithAsset:result];
dispatch_async(dispatch_get_main_queue(), ^{
[self.fetchedAssets addObject:assetWrapper];
});
}];
});
[self.tableView performSelector:#selector(reloadData) withObject:nil afterDelay:0.5];
}
How I load and call the button:
- (void)viewDidLoad
{
self.navigationItem.title = #"Loading";
UIBarButtonItem *shareButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAction
target:self
action:#selector(shareAction:)];
self.navigationItem.rightBarButtonItem = shareButton;
self.navigationItem.rightBarButtonItem.enabled = NO;
// TableView configuration.
self.tableView.contentInset = TABLEVIEW_INSETS;
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.allowsSelection = NO;
// Fetch the assets.
[self fetchAssets];
}
Should and did select fetched assets
#pragma mark - WSAssetsTableViewCellDelegate Methods
- (BOOL)assetsTableViewCell:(WSAssetsTableViewCell *)cell shouldSelectAssetAtColumn:(NSUInteger)column
{
BOOL shouldSelectAsset = (self.assetPickerState.selectionLimit == 0 ||
(self.assetPickerState.selectedCount < self.assetPickerState.selectionLimit));
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSUInteger assetIndex = indexPath.row * self.assetsPerRow + column;
WSAssetWrapper *assetWrapper = [self.fetchedAssets objectAtIndex:assetIndex];
if ((shouldSelectAsset == NO) && (assetWrapper.isSelected == NO))
self.assetPickerState.state = WSAssetPickerStateSelectionLimitReached;
else
self.assetPickerState.state = WSAssetPickerStatePickingAssets;
return shouldSelectAsset;
}
- (void)assetsTableViewCell:(WSAssetsTableViewCell *)cell didSelectAsset:(BOOL)selected atColumn:(NSUInteger)column
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
// Calculate the index of the corresponding asset.
NSUInteger assetIndex = indexPath.row * self.assetsPerRow + column;
WSAssetWrapper *assetWrapper = [self.fetchedAssets objectAtIndex:assetIndex];
assetWrapper.selected = selected;
// Update the state object's selectedAssets.
[self.assetPickerState changeSelectionState:selected forAsset:assetWrapper.asset];
// Update navigation bar with selected count and limit variables
dispatch_async(dispatch_get_main_queue(), ^{
if (self.assetPickerState.selectionLimit) {
self.navigationItem.title = [NSString stringWithFormat:#"%# (%lu/%ld)", [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName], (unsigned long)self.assetPickerState.selectedCount, (long)self.assetPickerState.selectionLimit];
}
});
if (self.assetPickerState.selectedCount == 0) {
self.navigationItem.rightBarButtonItem.enabled = NO;
}
else {
self.navigationItem.rightBarButtonItem.enabled = YES;
}
}
Work needed to below with example from the download code I have used before.
-(void)shareAction:(id)sender {
//Launch UIDocumentInteractionController for selected images
documentController =[[UIDocumentInteractionController alloc]init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath://Code needed here??//]];
documentController.delegate=self;
[documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}
What would be the best practice to do this?
Thanks.
UPDATE 8/4:
-(void)shareAction:(id)sender {
//Launch UIDocumentInteractionController for selected images
if (self.assetPickerState.selectedCount >= 1) {
documentController = [[UIDocumentInteractionController alloc] init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:#"public.image"]];
[documentController setDelegate:self];
[documentController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES];
}
}
Returns: Unable to get data for URL: The operation couldn’t be completed. (Cocoa error 260.)
Your interactionControllerWithURL: doesn't seem to be a problem but I have observed that -presentOpenInMenuFromRect: does not show if there are no apps that can open the file.
If your purpose is to share the file, and generally that doesn't mean open the file in the conventional sense, then instead of:
-presentOpenInMenuFromRect:inView:animated:
use
-presentOptionsMenuFromRect:inView:animated:
The former is an OpenInMenu and latter is an OptionsMenu.
For the tiny difference, check my related answer or check Apple doc directly
Example:
//this seems fine
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
//do this
[documentController presentOptionsMenuFromRect:CGRectZero
inView:self.view
animated:YES];
Also..., just before you present the documentInteractionController, it's good practice to specify the file's UTI so the documentInteractionController can populate itself with the appropriate options that can be performed & the list of all apps that can handle this file:
Example:
//assuming the file is a PDF
[documentController setUTI:#"com.adobe.pdf"];
//or... same thing but a more standardized way would be
[documentController setUTI:(NSString *)kUTTypePDF];
//but for this second style you'll need to add the `MobileCoreServices` framework
//to your project bundle and specify the following in your .h or .m
//#import <MobileCoreServices/MobileCoreServices.h>
Extra: Apple's Uniform Type Identifiers Reference
I try to show with QlPreviewController a pdf from internet url without download it.
This is my code:
NSURL* url2 = [NSURL URLWithString:#"http://wwww.myweb.com/files/terms_en.pdf"];
// Check if can be shown
if(![QLPreviewController canPreviewItem:url2]) {
// cant show document
NSLog(#"can't show document");
}else {
NSLog(#"can show document");
// Show the document in preview
// _previewItemURL = url;
QLPreviewController* preview = [[QLPreviewController alloc] init];
[preview setDataSource:url2];
}
But it didn't show anything. In addition I have a warning in the last sentence [preview setDataSource:url2] saying 'Sending 'NSURL *_strong' to parameter of incompatible type 'id
As per the documentation, QLPreviewController requires NSFileURL, i.e. local files. Download your web resource with other means (e.g. NSData dataWithContentsOfURL), write to disk, and then feed the local URL to it.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
QLPreviewController *previewController = [[QLPreviewController alloc] init];
[previewController setDataSource:self];
[previewController setDelegate:self];
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
}
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
{
return [self.arrayForPDFList count];
}
- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
NSString *pathForPdf =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
pathForPdf = [pathForPdf stringByAppendingFormat:#"/%#.pdf",[self.arrayForPDFList objectAtIndex:index]];
return [NSURL URLWithString:pathForPdf];
}