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

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.

Related

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

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];

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;
}

Watchkit , openParentApplication with WatchKit Extension

First times doesn't work "Null"( before open App in iPhone )
and some times doesn't work but i want one loop or timer for repeat this request for get result :
here is my code
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply
{
// Temporary fix, I hope.
// --------------------
__block UIBackgroundTaskIdentifier bogusWorkaroundTask;
bogusWorkaroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bogusWorkaroundTask];
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] endBackgroundTask:bogusWorkaroundTask];
});
// --------------------
__block UIBackgroundTaskIdentifier realBackgroundTask;
realBackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
reply(nil);
[[UIApplication sharedApplication] endBackgroundTask:realBackgroundTask];
}];
// Kick off a network request, heavy processing work, etc.
// Return any data you need to, obviously.
// reply(nil);
reply(#{#"Confirmation" : #"Text was received."});
[[UIApplication sharedApplication] endBackgroundTask:realBackgroundTask];
// NSLog(#"User Info: %#", userInfo);
}
Watch App Code
- (void)willActivate {
// This method is called when watch view controller is about to be visible to user
[super willActivate];
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:#"MyCamande", #"OK", nil];
[InterfaceController openParentApplication:dictionary reply:^(NSDictionary *replyInfo, NSError *error) {
NSLog(#"Reply received by Watch app: %#", replyInfo);
}];
}
how can recall for get finally result
Well, I would not recommend you using anything, related to network operations on watch itself. First of all because Apple does not recommend to do it for obvious reasons. The only network thing that is performed on the watch directly is loading images.
I have been struggling with network operations and watch for like a week and came to a conclusion, that the most stable way to do it right now is not obvious.
The main issue is that WKInterfaceController.openParentApplication(...) does not work as expected. One can not just request to open iPhone app and give back the response as is. There are tons of solutions stating that creating backgound thread in - (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply would work just fine, but it actually does not. The problem is that this method has to send reply(...); right away. Even creating synchronious requests won't help, you will keep receiving "error -2 iPhone application did not reply.." like 5 times our of 10.
So, my solution is following:
You implement:
func requestUserToken() {
WKInterfaceController.openParentApplication(["request" : "token"], reply: responseParser)
}
and parse response for error that might occur if there's no response from iPhone.
On iOS side
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply
{
__block UIBackgroundTaskIdentifier watchKitHandler;
watchKitHandler = [[UIApplication sharedApplication] beginBackgroundTaskWithName:#"backgroundTask"
expirationHandler:^{
watchKitHandler = UIBackgroundTaskInvalid;
}];
NSString *request = userInfo[#"request"];
if ([request isEqualToString:#"token"])
{
reply(#{#"token" : #"OK"});
[PSWatchNetworkOperations.shared loginUser];
}
dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)NSEC_PER_SEC * 1 ), dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
[[UIApplication sharedApplication] endBackgroundTask:watchKitHandler];
} );
}
This code just creates a background thread that forces iPhone to send a network request. Let's imagine you would have a special class in your iPhone app that would send these requests and send the answer to watch. For now, this is only accomplishable using App Groups. So you have to create an app group for your application and watchkit extension. Afterwards, I would recommend using MMWormhole in order to establish communication between your app and extension. The manual is pretty self-explaining.
Now what's the point of all this. You have to implement sending request to server and send response through wormhole. I use ReactiveCocoa, so example from my code is like this:
- (void)fetchShoppingLists
{
RACSignal *signal = [PSHTTPClient.sharedAPIClient rac_GET:#"list/my" parameters:#{#"limit":#20, #"offset":#0} resultClass:PSShoppingListsModel.class];
[signal subscribeNext:^(PSShoppingListsModel* shoppingLists) {
[self.wormHole passMessageObject:shoppingLists identifier:#"shoppingLists"];
}];
[signal subscribeError:^(NSError *error) {
[self.wormHole passMessageObject:error identifier:#"error"];
}];
}
As you see here I send back either response object, or error. Note, that all that you send through wormhole should be NSCoding-compatible.
Now on the watch you'll probably parse response like this:
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
PSWatchOperations.sharedInstance.requestUserToken()
PSWatchOperations.sharedInstance.wormhole.listenForMessageWithIdentifier("token", listener: { (messageObject) -> Void in
// parse message object here
}
})
}
So, to make a conclusion. You send request to parent application to wake up from background and start async operation. Send reply() back immediately. When you receive answer from operation send notification that you've got response. Meanwhile listen to response in your watchExtension.
Sorry, that was a lot of text, but I just hope it helps keep one's ass cool, because I've spent a lot of nerves on that.
May be you can try to explain the exact problem a little more clearly. But one thing you may want to do regardless is to make the openParentApp call in awakeWithContext: instead of willActivate.

Preload sqlite database creating by UIManagedDocument, running Ok in iphone simulator, refusing to work in iphone Device

I've been working on this problem for a week, and I googled and searched stack overflow, read about 40 posts, still can't fix my problem. here is what i did:
1.I wrote a testing app to create the sqlite database, and preload it with data.
2.I create myApp, and copied the preloaded DB to resource folder.
3.I wrote the following code to get the DB:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (!self.myDataBase) {
NSURL *url = [self localDocumentsDirectoryURL];
url = [url URLByAppendingPathComponent:#"myDB/"];
self.myDataBase = [[UIManagedDocument alloc] initWithFileURL:url];
}
return YES;
}
-(NSURL*)localDocumentsDirectoryURL {
static NSURL *localDocumentsDirectoryURL = nil;
if (localDocumentsDirectoryURL == nil) {
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory,NSUserDomainMask, YES ) objectAtIndex:0];
localDocumentsDirectoryURL = [NSURL fileURLWithPath:documentsDirectoryPath];
}
return localDocumentsDirectoryURL;
}
- (void)useDocument
{
if (![[NSFileManager defaultManager] fileExistsAtPath:[self.ICCarDataBase.fileURL path]])
{
[self.ICCarDataBase saveToURL:self.ICCarDataBase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {}];
}
else
{
[self.ICCarDataBase openWithCompletionHandler:^(BOOL success) {}];
}
}
- (void) setICCarDataBase:(UIManagedDocument *)carDataBase
{
if (_ICCarDataBase != carDataBase) {
_ICCarDataBase = carDataBase;
[self useDocument];
}
}
Then when I run myApp in Simulator, myApp successfully get the DB data, and when I run it in my iPhone, the myApp can't get the DB data.
I don't know if the SDK version matters, coz, the simulator is iphone 5.1, and my iPhone is 5.0 (jailbreak). And I don't use any 5.1 specific function in my App.
Some says that you should copy the DataBase to document dir first for it to work, I've tried the solution, still works ok in simulator, but no data in iPhone. Plus, I looked into iphone folders using iTool, myDB folder is already in the document dir.The post suggest the solution is here:Pre-load core data database in iOS 5 with UIManagedDocument
Other says I should use persistentStoreCoordinator directly. But I think UIManagedDocument could work in my situation, since it create a implicit persistentStoreCoordinator itself.
Any suggestion about what's wrong with myApp?
And anyone can tell me why ios wrap the sqlite DB with two layers of folders, and name the actual sqlite db persisentStore?
I've solved this problem, thanks to this postiPhone: Can access files in documents directory in Simulator, but not device
In this post he referenced this blog :Xcode resource groups and folder references when building for iPhone
After solving my problem, I've come to realize the reason that preload sqlite database won't work in device is: when Xcode copy database to the device from the bundle, the folder layers(myDB/StoreContent/persistentStore) wrapping the persistentStore is removed. So there is only a persistentStore file mixed with all other files in the device in the myApp.app bundle. And when you use UIManagedDocument to access sqlite database, it can only work with sqlite in such directory structure: myDB/StoreContent/persistentStore. So, with only a naked persistentStore file, the UIManagedDocument will create a whole new directory structure for you, with an empty persistentStore in it.
If someone can suggest a way for UIManagedDocument to work with the persistentStore file without folder layers, I would be interested.
And I use this code to access the DB after I successfully replicate the directory structure in my device bundle:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (!self.myDataBase) {
NSURL *url = [[NSBundle mainBundle] resourceURL];
url = [url URLByAppendingPathComponent:#"myDB/"];
self.myDataBase = [[UIManagedDocument alloc] initWithFileURL:url];
}
return YES;
}

Sent HTTP request with Credential in blackberry

I am trying to call HTTP request with network credential in blackberry. i have already implement on Java, Android it's working fine but not working on blackberry. Following step i have done in blackberry.
For set Network credential i have added three following jar.
commons-codec-1.6.jar
commons-httpclient-3.0.1.jar
commons-logging-1.1.1.jar
add this jar files are in blackberry project.
Following sample Code that work fine in Core Java.
try{
HttpClient client = new HttpClient();
GetMethod get = new GetMethod("http://www.google.com");
get.setDoAuthentication( true );
try {
int status = client.executeMethod( get );
System.out.println(status + "\n" + get.getResponseBodyAsString());
} finally {
get.releaseConnection();
}
}catch(Exception e){
System.out.println("Error:>>>>>>"+e);
}
Now there are not error on code but whenever try to click on application icon error face like "error starting appName: Module 'commons-httpclient-3.0.1' not found"
Can any one suggest what's this error say.
BB does not support HttpClient. But it does support J2ME's HttpConnection and is quite similar to HttpClient, so you can easily adjust with it. Here's some sample code to get you started:
try{
HttpConnection mConn = (HttpConnection)Connector.open(urlToPost);
mConn.setRequestMethod(HttpConnection.POST);
mConn.setRequestProperty("IF-Modified-Since", "20 Jan 2001 16:19:14 GMT");
mConn.setRequestProperty("User-Agent","Profile/MIDP-1.0 Configuration/CLDC-1.0");
mConn.setRequestProperty("Content-Language", "en-CA");
//---------------------------------------------------
mConn.setRequestProperty("User",usr);
mConn.setRequestProperty("pass",pass);
//---------------------------------------------------
catch(Exception e){//---handle your exceptions---//}
} finally {
mConn.close();//don't forget to close connections, only a limited number are available
}
This is a good article for beter understanding.

Resources