How to upload an image file in a background session (iOS)? - background-process

I am unable to upload an image from my device's Photos in a background session. When I call [session uploadTaskWithRequest:req fromFile:nsurl] the system immediately complains by sending
Failed to issue sandbox extension for file file:///var/mobile/Media/DCIM/103APPLE/IMG_3984.JPG, errno = 1
to the console. (A similar Stack Overflow issue is here)
However, if I create my NSURLSessionConfiguration with [NSURLSessionConfiguration defaultSessionConfiguration] (instead of [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:id], which I need) and if I construct an NSData object out of the NSURL and upload that instead of uploading straight from a file (which is required by a background session) then the upload succeeds. Btw I'm uploading files into our Rackspace Cloud account, and am able to do this successfully with a simple Postman PUT.
The problem occurs in my uploadObject method, which looks like:
-(void) uploadObject:(NSURL*)urlToBeUploadedIn
{
NSDictionary *headers = #{ #"x-auth-token": state.tokenID,
#"content-type": #"image/jpeg",
#"cache-control": #"no-cache" };
// create destination url for Rackspace cloud upload
NSString *sURL = [NSString stringWithFormat:#"%#/testing_folder/%#.jpg", state.publicURL, [state generateImageName]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:sURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:#"PUT"];
[request setAllHTTPHeaderFields:headers];
self.sessionIdentifier = [NSString stringWithFormat:#"my-background-session"];
// NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; // when I use this instead of the line below the sandbox error goes away
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:self.sessionIdentifier];
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromFile:urlToBeUploadedIn];
[uploadTask resume];
}
My call that invokes uploadObject: looks like:
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:state.arrImagesToBeUploaded options:nil];
PHAsset *phAsset = [fetchResult objectAtIndex:0]; // yes the 0th item in array is guaranteed to exist, above.
[phAsset requestContentEditingInputWithOptions:nil
completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
NSURL *imageURL = contentEditingInput.fullSizeImageURL;
[self uploadObject:imageURL];
}];
Btw I first validate the NSURL I send to uploadObject: with a call to fileExistsAtPath: so I know my reference to the file is good. Finally, my delegate calls
(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)dataIn
(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error does get invoked, although the data
do get called by the server (although the response won't parse) so, I am getting something back from the server which never correctly receives the image.

A solution is to first copy the image to be uploaded into the app's sandbox. I used:
NSError *err;
BOOL bVal = [myNSDataOb writeToURL:myDestinationURL options:0 error:&err];
and copied into my app's 'Documents' directory, but one might also use:
NSError *err;
BOOL bVal = [[NSFileManager defaultManager] copyItemAtURL:myImageURL toURL:myDestinationURL error:&err];

Related

NSCocoaErrorDomain Code=257 when trying to access "My Photo Stream" media in iOS 13

In iOS 13, I get an error when I try to access to "My Photo Stream" media, which doesn't exist in device.
Error Domain=NSCocoaErrorDomain Code=257 "ファイル“IMG_0010.JPG”を表示するためのアクセス権がないため、開けませんでした。" UserInfo={NSFilePath=/var/mobile/Media/PhotoStreamsData/8281221100/100APPLE/IMG_0010.JPG, NSUnderlyingError=0x283452820 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
But in iOS 12 and earlier, I don't get the error.
My actual code is like below.
// asset is Photo Stream media.
PHContentEditingInputRequestOptions *editOptions = [PHContentEditingInputRequestOptions new];
editOptions.networkAccessAllowed = YES;
editOptions.progressHandler = ^void(double progress, BOOL *stop) {};
[asset requestContentEditingInputWithOptions:editOptions
completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
NSError *error;
NSData *data = [NSData dataWithContentsOfURL:contentEditingInput.fullSizeImageURL
options:(NSDataReadingMappedIfSafe)
error:&error];
NSLog(#"%#", data); // "Error Domain=NSCocoaErrorDomain Code=257"
I found some people who are struggling with similar issues.
NSCocoaErrorDomain Code=257 file couldn’t be opened because you don’t have permission to view it : FileManager attributesOfItem returns nil in iOS13
I know Apple is putting so much effort into privacy.
So anything changed around it? And I'd like to know the way to solve my problem.

downloadTaskWithRequest wont download simultaneously

Okej guys. Here we go!!!
I have created a download manager in objective-C that uses NSURLSession.
I´ve got the manager to call a php script on my server, that creates an output file of a file located on the server(image in this case).
I need to call a php script so I can do the security checks on the call from objective-C.
Objective-C starts downloading the virtual file of the server and saves it to the temp directory on the iPhone. The only thing that doesn't work is simultaneously downloading of the files. If I start three download tasks with downloadTaskWithRequest, the first download task will hang the second download task until it´s finished.
If I trie the same thing with downloadTaskWithURL, I am going to get all the downloads downloading simultaneously, meaning no waiting.
What I want, is to download all files simultaneously, but with the downloadTaskWithRequest, not downloadTaskWithURL.
Code Init NSULRSession:
url = [NSURL URLWithString:kServerURL];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPMaximumConnectionsPerHost = 10;
session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
Code Request File From Server method:
The variable 'question' contains data for the server(Username, Password and file to download)
//Pack it into a NSData
NSString *dataString = [NSString stringWithFormat:#"message=%#",question];
NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
//Create a NSMutableURLRequest with method and body data
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = #"POST";
request.HTTPBody = data;
//Prepare for call to server
NSURLSessionTask *post = [session downloadTaskWithRequest:request];
//Start the task
[post resume];
Code File Finished Downloading method:
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
//Contains file destination name
NSString *file = [[calls objectForKey:downloadTask] objectAtIndex:4];
//Move temp file to new location
NSString *destination = [[[[GlobalClass sharedManager] storagewraper] filemanager] moveFile:location.path name:file];
}
-----------------------------------------------------Thanks in advance----------------------------------------------------

Is there any way to remove encryption from an existing Realm database?

We are using the Objective-C version of Realm, version 2.0.2. The database is currently encrypted and is in the field.
Intermittent crashes on the startup of Realm have been occurring, with an error message of "Unable to open a Realm at path ... Realm file decryption failed". We are at the latest version available of Realm, and have not been able to find a solution.
We don't really need the database to be encrypted on the device, so we would like to consider removing the encryption. Is this an option, and if so, how would we migrate the existing encrypted databases?
You can use writeCopyToURL:encryptionKey:error: with a nil encryption key to write an unencrypted copy, and then move that over the original file:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
RLMRealmConfiguration *confg = [[RLMRealmConfiguration alloc] init];
config.encryptionKey = ...;
NSURL *tempUrl = [NSURL URLWithString:[NSTemporaryDirectory() stringByAppendingPathComponent:"temp.realm"]];
// Open the Realm within an autoreleasepool so that it's closed before we try
// to overwrite the original file
#autoreleasepool {
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
[realm writeCopyToURL:tempUrl encryptionKey:nil error:nil];
}
[[NSFileManager defaultManager] moveItemAtURL:tempUrl toURL:config.fileUrl error:nil];
// ... other didFinishLaunchingWithOptions things ...
return YES;
}

Import an existing SQLite database into an iOS Phonegap app

I've an existing SQLite database called data_items.sqlite. This database includes about 10 tables and some initial data which I would like to import into XCode to open the database with the Phonegap Plugin in this way:
function onDeviceReady() {
var db = window.sqlitePlugin.openDatabase("data_items.sqlite", "1.0", "PhoneGap Demo", 200000);
...
}
How can I import the datafile? Where do I have to copy the file?
First create database as u used name data_items.sqlite and remove .sqlite extension. Then drag this db at Resources directory in xCode and follow next .
Choose option for adding file box will appear
check checkbox says 'Copy items into destination group's folder (if needed)' and finish.
You will see the Database file as sub list of Resources Directory
Sorry I don't have enough reputation to post images here
Now follow the link to copy this database file into location
How to copy sqlite database when application is launched in iOS?
I used the following code before the #end at last line in AppDelegate.m
- (void) copyDatabaseIfNeeded{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
_dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:_dbPath];
if(!success){
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"data_items"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:_dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}}
/********* Database Path *********/
- (NSString *) getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"data_items"];
}
And Copy the line
[self copyDatabaseIfNeeded];
after the code
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
That's it. Use your code
function onDeviceReady() {
var db = window.sqlitePlugin.openDatabase("data_items", "1.0", "data_items", 200000);
...
}
You can also edit database directly in from the copied location. Use following link
Where does the iPhone Simulator store its data?
It appears not to be possible to access the assets folder from PhoneGap, so you have to write a native plugin to copy the database file:
Prepopulate SQLite DataBase in PhoneGap Application

How to log into website from iOS device?

Someone I work with created a website that he wants to use to provide a service. They run a php script when the user taps Login that checks username/password/etc
Now I want to write an app that would allow logging in and also retrieving data, as one would on the website. How can I pass the login info from the iOS device to that PHP script that is run on the website? And after I'm logged in, how can I check and retrieve the data?
Do I need to ask him for an API?
responseData = [[NSMutableData data] retain];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.yourwebsite.com/login.php"]];
NSString *params = [[NSString alloc] initWithFormat:#"user=myuser&pass=mypass"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];

Resources