UIActivityViewController not showing AirDrop option in iOS11 - objective-c

I have some code that shows an UIAcvityViewController for exporting a custom object from my app, formatted as JSON. This code works fine in previous versions of iOS but now fails it iOS 11. The problem is that when the Activity View Controller displays, it does not display the Airdrop panel or available recipient devices at all. The document is an NSDictionary that is encoded and written to a NSData object and then written to disk and referenced by an NSURL. As I stated, this code worked fine and still works fine in previous versions of iOS. I also have another place where I am using the UIActivityViewController to export an image file, and Airdrop continues to work fine in iOS 11. I am assuming that the issue has to do with the format of the file being exported and referenced by the URL I am referencing in the url key of the ActivityProvider, but I have tried every way of outputting and encoding this object that makes sense. Here is the code I am using:
NSString *textToShare = #"I am sharing this record with you!";
NSURL* url = [self.record exportNoteToURL];
NSMutableArray* activityProviders = [[NSMutableArray alloc]initWithCapacity:0];
NoteRecordActivityProvider *provider = [[NoteRecordActivityProvider alloc] initWithPlaceholderItem:#{#"body":textToShare, #"url":url}];
[activityProviders addObject:provider];
//Initialize the ActivityViewController
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityProviders applicationActivities:applicationActivities];
NSArray *excludeActivities = #[UIActivityTypePostToFacebook,
UIActivityTypePostToTwitter,
UIActivityTypePostToWeibo,
//UIActivityTypeMessage,
//UIActivityTypeMail,
//UIActivityTypePrint,
UIActivityTypeCopyToPasteboard,
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToFlickr,
UIActivityTypePostToVimeo,
UIActivityTypePostToTencentWeibo,
//UIActivityTypeAirDrop,
UIActivityTypeOpenInIBooks];
activityController.excludedActivityTypes = excludeActivities;
[activityController setValue:[NSString stringWithFormat:#"Record: %#", self.record.title] forKey:#"subject"];
activityController.popoverPresentationController.barButtonItem = (UIBarButtonItem*)sender;
activityController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if (completed)
{
NSLog(#"The Activity: %# was completed", activityType);
}
else
{
NSLog(#"The Activity: %# was NOT completed", activityType);
}
[FileSystemProvider clearExportsDirectory];
};
[self presentViewController:activityController animated:YES completion:nil];
Following is the code that exports the dictionary to the URL, which seems to be working properly.
#pragma mark Document Export
-(NSURL*) exportNoteToURL
{
NSMutableDictionary* dict =[[NSMutableDictionary alloc]initWithCapacity:0];
// 1 Create Dictionary
NSDictionary* noteDict = [self getSettingsDictionary];
[dict setValue:noteDict forKey:#"Note"];
// 2 Get File Name and create file path
NSString* fullFilePath = [[FileSystemProvider documentPath]stringByAppendingPathComponent:#"Exports"];
NSLog(#"Export Path: %#", fullFilePath);
[MiscUtilities createDirectory:fullFilePath];
NSString* fileName = #"ExportedNoteRecord.lgz";
fileName = self.title;
fileName = [fileName stringByReplacingOccurrencesOfString:#" " withString:#""];
fileName = [MiscUtilities SanitizeFileNameString:fileName];
fileName = [NSString stringWithFormat:#"%#%#", fileName, #".lgz"];
fullFilePath = [fullFilePath stringByAppendingPathComponent:fileName];
// 3 Write dictionary to FileSystem
NSURL* url = [[NSURL alloc]initFileURLWithPath:fullFilePath];
BOOL res = [dict writeToURL:url error:&error];
if (res)
{
return url;
}
else
{
return nil;
}
}

The problem is that your activityViewControllerPlaceholderItem returns a Dictionary. The type you return here is used as an indication of what type of object you are vending. Airdrop doesn't want to receive a mysterious Dictionary so it doesn't respond. If what are vending is a file URL, you should have been returning a URL.

Related

Is NSUserName() not working in xcode6?

NSUserName() doesn't seem to be working for me in Xcode 6 while developing iOS apps.
I was using it to get the desktop directory to save a core data seed to my desktop during development.
NSString* deskStorePath = [NSString stringWithFormat:#"/Users/%#/Desktop/newMySQL.CDBStore", NSUserName()];
I had to change my code to:
#define USER_NAME #"myusername"
NSString* deskStorePath02 = [NSString stringWithFormat:#"/Users/%#/Desktop/newMySQL.CDBStore", USER_NAME];
Now NSUserName() returns nothing in Xcode 6, but had worked fine in Xcode 5.
NSString* myname = NSUserName();
NSString* myfullname = NSFullUserName();
NSLog(#"name : %# - %#",myname,myfullname);
Is it a bug?
Do I need to import a library now?
Or is there an alternative to get the current OSX username during app development?
edit: (This is the method I'm using to save the core data seed store to desktop which I then add to my dev environment)
- (void) saveSeedToDesktop
{
[self testNSUser];
NSString* myDBName = [NSString stringWithFormat:#"%#.sqlite",CD_FILE_NAME];
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent : myDBName];
NSString* deskStorePath = [NSString stringWithFormat:#"/Users/%#/Desktop/newMySQL.CDBStore", USER_NAME];
NSError*error;
if (![[NSFileManager defaultManager] copyItemAtPath:storePath toPath: deskStorePath error:&error]){
NSLog(#"error with path : %#",error);
}
else {
NSLog(#"Copied");
}
}
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) lastObject];
}
This is a test class:
- (void) testNSUser {
NSString* myname = NSUserName();
NSString* myfullname = NSFullUserName();
NSLog(#"name : %# - %#",myname,myfullname);
__unused NSString* deskStorePathTest01 = [NSString stringWithFormat:#"/Users/this_is_my_name/Desktop/test.txt"]; //works
__unused NSString* deskStorePathTest02 = [NSString stringWithFormat:#"~/Desktop/test.txt"];
__unused NSString* deskStorePathTest03 = [NSString stringWithFormat:#"/Users/~/Desktop/test.txt"];
__unused NSString* deskStorePathTest04 = [NSString stringWithFormat:#"/~/Desktop/test.txt"];
[self fileExistsTest:deskStorePathTest01];
[self fileExistsTest:deskStorePathTest02];
[self fileExistsTest:deskStorePathTest03];
[self fileExistsTest:deskStorePathTest04];
}
- (void) fileExistsTest : (NSString*)storePath {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *pathForFile = storePath;
if ([fileManager fileExistsAtPath:pathForFile]){
NSLog(#"exists : %#",storePath);
}
else {
NSLog(#"doesnt exist");
}
}
We had the same issue with assets produced by running the app in the simulator. I realised that the app itself is stored below my home directory so I could access my username from that:
NSString *userName = NSUserName();
#if TARGET_IPHONE_SIMULATOR
if (userName.length == 0)
{
NSArray *bundlePathComponents = [NSBundle.mainBundle.bundlePath pathComponents];
if (bundlePathComponents.count >= 3
&& [bundlePathComponents[0] isEqualToString:#"/"]
&& [bundlePathComponents[1] isEqualToString:#"Users"])
{
userName = bundlePathComponents[2];
}
}
#endif
Obviously for development only.
It's working for me, on the device, anyway. It does not seem to work on the simulator.
-(id) init
{
self = [super initWithStyle:UITableViewStyleGrouped];
if(self)
{
//Custom initialization.
NSString *u = NSUserName();
NSLog(#"%#", u);
}
return self;
}
Output is:
2014-10-05 20:45:38.451 [my app business] mobile
If I'm understanding what you're trying to accomplish here, though, I think the prescribed way of initializing the Core Data store with default data may be to programmatically add it. At least, that's what I took away from the docs. I'm pretty sure they say somewhere that you're not supposed to manipulate the Core Data store file outside of the API.

Vfr-Reader crashes on assert(range.location != NSNotFound);

I am using thisopen source control called Vfr Reader to show pdf files in my app. All was working on iOS 7. After iOS update app crashes when I try on open a pdf file.
I am using this code to initialize pdf reader.
NSString *fileName = [[NSBundle mainBundle] pathForResource:#"PdfName" ofType:#"pdf"];
ReaderDocument *document = [ReaderDocument withDocumentFilePath:fileName password:nil];
if (document != nil)
{
ReaderViewController *readerViewController = [[ReaderViewController alloc] initWithReaderDocument:document];
readerViewController.delegate = self;
readerViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
readerViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:readerViewController animated:YES completion:Nil];
}
App crashes in this fuction of vfr
+ (NSString *)relativeFilePath:(NSString *)fullFilePath
{
assert(fullFilePath != nil); // Ensure that the full file path is not nil
NSString *applicationPath = [ReaderDocument applicationPath]; // Get the application path
NSRange range = [fullFilePath rangeOfString:applicationPath]; // Look for the application path
assert(range.location != NSNotFound); // **Crashes here**
return [fullFilePath stringByReplacingCharactersInRange:range withString:#""]; // Strip it out
}
On crash debugger shows these values.
fullFilePath = #"/Users/GuruTraxiOSDev01/Library/Developer/CoreSimulator/Devices/CC9412A6-9A95-4F46-89BA-8ECC13D0AF19/data/Containers/Bundle/Application/D2DC440B-F010-4575-93FD-3CB05BFF4F78/AppName.app/PdfName.pdf" 0x798c9b30
range = location=2147483647, length=0
applicationPath =#"/Users/GuruTraxiOSDev01/Library/Developer/CoreSimulator/Devices/CC9412A6-9A95-4F46-89BA-8ECC13D0AF19/data/Containers/Data/Application/32D612DE-FFD2-4C1E-B403-CDA177B460A6" 0x798b46b0
I already confirmed the file's existence.
Can anyone help please!
EDIT: This question solved crash on file load. But app still crashes on
CGContextDrawPDFPage(context, thePDFPageRef);
I was facing the same issue, so I made some changes to the Library Files which should not be an option as such but in this case I didn't have any choice to get it to work. So to make your code work follow the instruction below:
Go to ReaderDocument.m file and make the following changes:
+ (NSString *)documentsPath
{
//Make changes to return the NSBundle path.
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSFileManager *fileManager = [NSFileManager new]; // File manager instance
NSURL *pathURL = [fileManager URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
// return [pathURL path]; // Path to the application's "~/Documents" directory // Code changes.
return bundlePath;
}
If you had a breakpoint just delete it, that solve it for me.
Breakpoint navigator => select the breakpoint then delete

Drop e-mail from mail.app into NSWindow object

I have an cocoa app where I would like to accept e-mails from mail.app dragged into the main window of the app. I have in my applicationDidFinishLaunching:
[_window registerForDraggedTypes:
[NSArray arrayWithObjects:
NSFilenamesPboardType,
(NSString *)kPasteboardTypeFileURLPromise, nil]]; //kUTTypeData
[_window setDelegate:(id) self];
This works fine, I can receive a document, in my performDragOperation: using
NSArray * files = [sender namesOfPromisedFilesDroppedAtDestination:url];
However, this only lets me drag the emails one-by-one. If I mark several emails, everything seems OK until I drop, then nothing happens. The performDragOperation is not even called.
I have tried to add kUTTypeData to the registerForDraggedTypes..., and then I get the performDragOperation... called, but then I cannot use the namesOfPromisedFilesDroppedAtDestination:url as it returns a nil pointer.
When I had the kUTTypeData included in the register... I included this in the performDragOperation to see what types in drag:
pboard = [sender draggingPasteboard];
NSLog(#"perform drag entered, %#", [pboard types]);
With the following result:
2013-07-25 15:09:50.771 BO2ICAL[1672:303] perform drag entered, (
"dyn.ah62d4rv4gu8y4zvanr41a3pwfz30n25wqz4ca5pfsr30c35feb4he2pssrxgn6vasbu1g7dfqm10c6xeeb4hw6df",
"MV Super-secret message transfer pasteboard type",
"dyn.ah62d4rv4gu8zg7puqz3c465fqr3gn7bakf41k55rqf4g86vasbu1g7dfqm10c6xeeb4hw6df",
"Super-secret Automator pasteboard type"
)
While the list for single e-mails are:
2013-07-25 15:14:30.096 BO2ICAL[1672:303] perform drag entered, (
"dyn.ah62d4rv4gu8y4zvanr41a3pwfz30n25wqz4ca5pfsr30c35feb4he2pssrxgn6vasbu1g7dfqm10c6xeeb4hw6df",
"MV Super-secret message transfer pasteboard type",
"dyn.ah62d4rv4gu8zg7puqz3c465fqr3gn7bakf41k55rqf4g86vasbu1g7dfqm10c6xeeb4hw6df",
"Super-secret Automator pasteboard type",
"dyn.ah62d4rv4gu8yc6durvwwa3xmrvw1gkdusm1044pxqyuha2pxsvw0e55bsmwca7d3sbwu",
"Apple files promise pasteboard type",
"public.url",
"CorePasteboardFlavorType 0x75726C20",
"dyn.ah62d4rv4gu8yc6durvwwaznwmuuha2pxsvw0e55bsmwca7d3sbwu",
"Apple URL pasteboard type",
"public.url-name",
"CorePasteboardFlavorType 0x75726C6E",
"com.apple.pasteboard.promised-file-content-type",
"com.apple.pasteboard.promised-file-url",
"dyn.ah62d4rv4gu8y6y4usm1044pxqzb085xyqz1hk64uqm10c6xenv61a3k",
NSPromiseContentsPboardType
)
Does anyone have any advice how to do this correctly in order to accept multiple e-mails?
I have found a solution to this. I found that the data provided in the mode "kUTTypeData" gave me enough data to grab the files directly from the mail.app mailbox.
In the mbox folder, there is a folder with a long sequence of numbers and dashes, there was no trace of this name anywhere in the mailbox hierarchy, but since this only contains this folder and an info.plist file, I used this function to grab that name: Update: implemented regexp check since the folder sometimes contains sub-mailboxes that can have a longer name...
-(NSString*)FindCodedFolderInMailbox:(NSString*)mailboxpath {
NSString *uuid_regexp = #"[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}";
NSPredicate *uuid_test = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", uuid_regexp];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *fileList = [fileManager contentsOfDirectoryAtPath:mailboxpath error:nil];
for (NSString * file in fileList) {
if ([uuid_test evaluateWithObject: file]){
return file;
}
}
return nil;
}
Then the section where I find there is no "NSPromiseContentsPboardType", but instead a "Super-secret Automator pasteboard type", I wrote the following section (There is some NSLog entries I intend to remove, but here it is:
} else if ( [[pboard types] containsObject:#"Super-secret Automator pasteboard type"] ) {
NSFileManager *fileManager = [NSFileManager defaultManager];
// Create the URL for the destination folder and ensure it exists.
NSURL *applicationFilesDirectory = [self applicationFilesDirectory];
NSURL *url = [applicationFilesDirectory URLByAppendingPathComponent:#"documents"];
BOOL isDir;
if (!([fileManager fileExistsAtPath:[url path] isDirectory:&isDir] && isDir)) {
NSError * error = nil;
[ fileManager createDirectoryAtURL:url withIntermediateDirectories: YES attributes:nil error:&error];
if (error) {
[[NSApplication sharedApplication] presentError:error];
}
}
BOOL ok = false;
// locate the mailbox path....
NSString *mailboxpath = [pboard stringForType:#"MV Super-secret message transfer pasteboard type"];
NSLog(#"Mailboxpath: %#", mailboxpath);
NSString * codedFolder = [self FindCodedFolderInMailbox:mailboxpath];
if (codedFolder) {
NSString * codedpath = [NSString stringWithFormat:#"file://%#/%#/Data", mailboxpath, codedFolder];
NSURL * mb1 = [NSURL URLWithString:codedpath];
NSLog(#"Directory:%#", mb1);
NSArray *msgArray = [pboard propertyListForType:#"Super-secret Automator pasteboard type"];
if (msgArray) {
for (NSDictionary *msg in msgArray) {
// Locate the message....
NSNumber * msgID = [msg valueForKey:#"id"];
NSLog(#"Melding(%#):%#", msgID, msg);
NSString * filename = [NSString stringWithFormat:#"%#.emlx", msgID];
// second and first letter of id
NSString * idSec = [[msgID stringValue]substringWithRange:(NSRange){1, 1}];
NSString * idFirst = [[msgID stringValue]substringWithRange:(NSRange){0, 1}];
NSString * subpath = [NSString stringWithFormat:#"%#/%#/Messages/%#",idSec, idFirst, filename];
NSURL * thisFilePath = [mb1 URLByAppendingPathComponent:subpath];
if ([fileManager fileExistsAtPath:[thisFilePath path]]) {
NSURL *destpath = [url URLByAppendingPathComponent:filename];
NSError * error = nil;
[fileManager copyItemAtURL:thisFilePath toURL:destpath error:&error];
if (error) {
[[NSApplication sharedApplication]presentError:error];
} else {
[self ParseEmlMessageforPath:[destpath path] filename:filename];
}
}
}
}
}
And here we go.... :-)

how to show JSON result data in UITextView in objective c

Please consider this code:
NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:[ NSURL URLWithString:url ]]; // Pulls the URL
NSLog(#"jsonreturn#########=%#",jsonreturn); // Look at the console and you can see what the restults are
NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.nullObject = NULL;
NSError *error = nil;
NSDictionary *dictt = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
NSLog(#"###dict=%#", dictt);
if (dictt) {
rowsForQuestion = [[dictt objectForKey:#"faqdetails"] retain];// NSArray rowsForQuestion
}
[jsonreturn release];
// I have got this data is in console NOW I WANT TO PRINT IT UITextView but HOW I can do it
faqdetails = (
{
faqAns = "Yes, Jack Kalis is the best crickter";
faqQues = "who is the best cricketer in present year?";
}
);
}
Your question isn't particularly clear regarding what you want to show where, but dropped text into a UITextView couldn't be easier.
[yourTextView setText: [[rowsForQuestion objectAtIndex: 0] objectForKey: #"faqQues"]];
The above code grabs the first dict from rowsForQuestion, and puts its value for #"faqQues" into a UITextView.
Assuming you have a UITextView instance called myTextView, made either programatically or through IB, try this:
[myTextView setText:faqdetails];

ObC : app crashes after returning NSMutableArray?

I am new to ObC and have a problem that i just cant fix. There may be other issues as well but the main issue is this:
Starting the app
Press button = load new view
In the new viewDidLoad i call another object/function and send a NSMutableArray
Process data and send back a NSMutableArray
App crash, see comment where. Most often when i go back and back again but sometimes the first time
As i am new to this i guess i do a lot of this wrong but could someone nice take a look at the code and give me some advice. I would assume i have problem with releasing something.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#" ");
NSLog(#"viewDidLoad ");
NSLog(#" ");
NSLog(#">>Processing prepareGame<<");
NSMutableArray *propArray1 = [[NSMutableArray alloc] initWithObjects:#"9999", nil]; //Init with dummy numbers
AccessPropertiesFile *readMyProperties = [AccessPropertiesFile new]; //Init function call to read file
NSLog(#"Prepare to call readProperties");
propArray1 = [readMyProperties readPropertiesFile:propArray1];
NSLog(#"Back from readProperties:error after this");
/*
for (NSString *element in propArray1) {
NSLog(#"Elements in prop2Array; %#", element);
}
*/
[readMyProperties release];
[propArray1 release];
}
-(NSMutableArray *)readPropertiesFile:(NSMutableArray *)readDataArray {
NSLog(#"Processing readProperties");
// For error information
NSError *error;
//Prepare File Manager
NSString *filePath = [self dataFilePath];
NSFileManager *fileMgr;
fileMgr = [NSFileManager defaultManager];
NSArray *propertiesArray = [NSArray alloc]; //Alloc array
//Check from what module the call is coming from to ecide what to do
if ([fileMgr fileExistsAtPath: filePath] == NO) {
NSLog (#"File not found");
//File does not exists, this is the first time the game starts
//Set up default parameters
NSString *fileString =#"0\n30\n30\n10\n1\n1\n1\n2\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n";
// Write default parameters to file
[fileString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
propertiesArray = [fileString componentsSeparatedByString:#"\n"]; // each line, adjust character for line endings
}
else { //File exists
NSLog (#"File exists");
NSString *fileString = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding error:nil]; // reads file into memory as an NSString
propertiesArray = [fileString componentsSeparatedByString:#"\n"]; // each line, adjust character for line endings
}
//Clean readDataArray
[readDataArray removeAllObjects];
//Populate return array
for (NSString *element in propertiesArray) {
//NSLog(#"Elements in propertiesArray; %#", element);
[readDataArray addObject:element];
}
NSLog(#"readDataArray: %#", readDataArray);
[propertiesArray release];
[readDataArray autorelease];
NSLog(#"returning from readProperties");
return readDataArray;
}
#end
You are over-releasing readDataArray (known as propArray1 in the method that didn't create it). You create it and autorelease it in your second method, then you release it again at the end of your first method (where it wasn't created).
I suggest you use Analyze feature that comes with latest XCode. It is a good feature that I always use to track if I forget to release or release too much.
I also spotted that you also over-release the propertiesArray because it contains the result from [fileString componentsSeparatedByString:], which will be autorelease according to Cocoa convention.