-1

Is there a way to listen to the file system change while an iPhone app is in the background? I want to create a cloud hosting app that will automatically upload your photos to the cloud if you add a new file without having to open the app first.

For example, if a user takes a new photo or takes a screenshot or a recording. Can I be notified that an item has been added to the filesystem?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • Do you want to take cloud backups of the user SMS and Apple payments too? –  Sep 04 '17 at 09:13
  • not possible to access the app in background. Try for alternatives – Gagan_iOS Sep 04 '17 at 09:13
  • @Sneak No, I want to make cloud backups of storage intensive photos and videos. The exact same way that Google Drive and iCloud works...You get what I'm driving at? Thanks – shoriwa-shaun-benjamin Sep 04 '17 at 09:20
  • Oh my bad, I was just curious since I saw your recent questions to simulate taking device screenshots and syncing contacts in the background outside of the app, I thought maybe you want to sync the other services too. Good luck my friend –  Sep 04 '17 at 09:21
  • @Gagan_iOS So how does Google Drive for iOS work? It allows for automatic backups of your photos and videos while in the background? – shoriwa-shaun-benjamin Sep 04 '17 at 09:24
  • I did one of my project very long ago, check my answer – karthikeyan Sep 04 '17 at 09:26
  • @Sneak FYI, yes a screenshot is stored as an image in your device storage. I don't know how you came to the conclusion of Apple Payments. That was clearly a caustic remark that you made. But anyways, good luck to you too with the trolling... – shoriwa-shaun-benjamin Sep 04 '17 at 09:29
  • A screenshot is stored on the device, but the process of taking a screenshot as per your question, or accessing the contacts or the file system while the app is in background, is something else. All your questions more or less involve security risks for the user, thats the remark I made. Let's avoid further chatting in the comment section keep things relevant to your question. –  Sep 04 '17 at 09:44
  • @Sneak I'm not trying to automate taking a screenshot or a photo. Where are you getting this from? I merely want to be notified so that my cloud service app can upload it online, with the user's prior consent. – shoriwa-shaun-benjamin Sep 04 '17 at 09:49

1 Answers1

2

You can do this with Photos Framework which is announced iOS8 release.

Read Documentation about change observer Link

Apple sample sample

Change observing. Use the shared PHPhotoLibrary object to register a change handler for the assets and collections you fetch. Photos tells your app whenever another app or device changes the content or metadata of an asset or the list of assets in a collection. PHChange objects provide information about object state before and after each change with semantics that make it easy to update a collection view or similar interface

You can take photos if any update on photos app, by using **photos framework

First you need to register photos observer

- (void)applicationWillTerminate:(UIApplication *)application {
    [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
}



 - (void)applicationDidBecomeActive:(UIApplication *)application {
        [FBSDKAppEvents activateApp];
        [[UIApplication sharedApplication] endBackgroundTask:UIBackgroundTaskInvalid];
        [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
        //    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        //        //Background Thread
        //        isBackgroundOrForeground = YES;
        //        [self getGreenEvent];
        //        dispatch_async(dispatch_get_main_queue(), ^(void){
        //            //Run UI Updates
        //        });
        //    });

    }
- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"=== DID ENTER BACKGROUND ===");
    bgTask = [[UIApplication  sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    }];

    if (bgTask == UIBackgroundTaskInvalid) {
        NSLog(@"This application does not support background mode");
    } else {
        //if application supports background mode, we'll see this log.
        NSLog(@"Application will continue to run in background");
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            if (status == PHAuthorizationStatusAuthorized) {
                [PHPhotoLibrary.sharedPhotoLibrary registerChangeObserver:self];
            }
        }];
        [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
        isBackgroundOrForeground = NO;
        NSString *oAuthToken = [[NSUserDefaults standardUserDefaults]stringForKey:KEY_ACCESS_TOKEN];
        if(oAuthToken.length!=0 || oAuthToken!=nil)
            [self getGreenEvent];
    }
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

pragma mark - PHPhotoLibraryChangeObserver

- (void)photoLibraryDidChange:(PHChange *)changeInstance {
    NSLog(@"content being changed");
    /*
     Change notifications may be made on a background queue. Re-dispatch to the
     main queue before acting on the change as we'll be updating the UI.
     */
    __block BOOL reloadRequired = NO;
    __block NSIndexSet *removedIndex;
    __block NSIndexSet *insertedIndexes;
    dispatch_async(dispatch_get_main_queue(), ^{
        // Loop through the section fetch results, replacing any fetch results that have been updated.
        NSMutableArray *updatedSectionFetchResults = [self.sectionFetchResults mutableCopy];
        //        __block BOOL reloadRequired = NO;
        [self.sectionFetchResults enumerateObjectsUsingBlock:^(PHFetchResult *collectionsFetchResult, NSUInteger index, BOOL *stop) {
            PHFetchResultChangeDetails *changeDetails = [changeInstance changeDetailsForFetchResult:collectionsFetchResult];
            removedIndex = changeDetails.removedIndexes;
            insertedIndexes = changeDetails.insertedIndexes;
            if (changeDetails != nil) {
                [updatedSectionFetchResults replaceObjectAtIndex:index withObject:[changeDetails fetchResultAfterChanges]];
                reloadRequired = YES;
                self.sectionFetchResults = updatedSectionFetchResults;
                if(insertedIndexes != nil){
                    [self backgroundUpload];
                }else{
                }

            }

        }];
        if (reloadRequired) {
            self.sectionFetchResults = updatedSectionFetchResults;

        }

    });

}
-(void)getAllPhotosFromCamera{
    PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
    allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
    PHFetchResult *allPhotos = [PHAsset fetchAssetsWithOptions:allPhotosOptions];
    PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
    // Store the PHFetchResult objects and localized titles for each section.
    self.sectionFetchResults = @[allPhotos, smartAlbums, topLevelUserCollections];
}
-(NSMutableArray *)getNumberOfPhotoFromCameraRoll:(NSArray *)array{
    PHFetchResult *fetchResult = array[1];
    int index = 0;
    unsigned long pictures = 0;
    for(int i = 0; i < fetchResult.count; i++){
        unsigned long temp = 0;
        temp = [PHAsset fetchAssetsInAssetCollection:fetchResult[i] options:nil].count;
        if(temp > pictures ){
            pictures = temp;
            index = i;
        }
    }
    PHCollection *collection = fetchResult[index];

    if (![collection isKindOfClass:[PHAssetCollection class]]) {
        // return;
    }
    // Configure the AAPLAssetGridViewController with the asset collection.
    PHAssetCollection *assetCollection = (PHAssetCollection *)collection;
    PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
    self. assetsFetchResults = assetsFetchResult;
    self. assetCollection = assetCollection;
    self.numberOfPhotoArray = [NSMutableArray array];
    for (int i = 0; i<[assetsFetchResult count]; i++) {
        PHAsset *asset = assetsFetchResult[i];
        [self.numberOfPhotoArray addObject:asset];
    }
    NSLog(@"%lu",(unsigned long)[self.numberOfPhotoArray count]);
    return self.numberOfPhotoArray;
}

Where bgTask is global object of

UIBackgroundTaskIdentifier bgTask;

@property (nonatomic, strong) NSArray *sectionFetchResults;
@property (nonatomic, strong) PHFetchResult *assetsFetchResults;
@property (nonatomic, strong) PHAssetCollection *assetCollection;
@property (nonatomic, strong) NSMutableArray *numberOfPhotoArray;
karthikeyan
  • 3,821
  • 3
  • 22
  • 45
  • Thanks. This is working for me. One question. I am getting the "loadDatabase background task assertion expired." exception in my logs (which means it ran for longer than 3 minutes in the background). Does this mean my app will get rejected from the appstore? Or maybe this doesnt matter? – shoriwa-shaun-benjamin Sep 04 '17 at 11:07
  • it is not related to app reject from app store, but i am not sure about this exception. You better make an another question – karthikeyan Sep 04 '17 at 11:12
  • 1
    An app is only allowed to be live for 3 minutes in the background. Thats why its saying that. Was asking if yours ever got rejected for listening in the background like that for more than 3 minutes. But ok, I will create another question. Thanks again! you were a huge help! – shoriwa-shaun-benjamin Sep 04 '17 at 11:15
  • welcome, i never get rejected from app store, you better read about background task limitation Here some explanation about BG task https://stackoverflow.com/questions/22679845/ios7-background-task-myapp-has-active-assertions-beyond-permitted-time – karthikeyan Sep 04 '17 at 11:17