iOS Question [SOLVED via workaround] Capturing ActivityViewController error messages

JackKirk

Well-Known Member
Licensed User
Longtime User
Hi,

I'm using https://www.b4x.com/android/forum/t...pp-with-activityviewcontroller.73159/#content to share photos with other applications.

Have had it all working for some time but just now have discovered a problem.

If the photo is too large (ie pixels wide x pixel high - NOT file size) the share will fail to some apps with a log message:

viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}

However all I get from the _Complete event is a boolean success/failure which could also mean the user aborted the share.

I would like to be able to give the user the option to downsize the photo when this occurs but there does not appear to be a way to programmatically get the error message.

Any clues?

Thanks in anticipation...
 

JackKirk

Well-Known Member
Licensed User
Longtime User
Digging into iOS documentation (basically a no-go area for me) there is:
https://developer.apple.com/documentation/uikit/uiactivityviewcontroller/completionwithitemshandler

which has:

activityType
The type of the service that was selected by the user. For custom services, this is the value returned by the activityType method of a UIActivity object. For system-defined activities, it is one of the strings listed in "Built-in Activity Types” in UIActivity.
Comment: presumably the ActivityType parameter of the _Complete event of https://www.b4x.com/android/forum/t...m-your-app-with-activityviewcontroller.73159/

completed
true if the service was performed or false if it was not. This parameter is also set to false when the user dismisses the view controller without selecting a service.
Comment: presumably the Success parameter of the _Complete event of https://www.b4x.com/android/forum/t...m-your-app-with-activityviewcontroller.73159/

returnedItems
An array of NSExtensionItem objects containing any modified data. Use the items in this array to get any changes made to the original data by an extension. If no items were modified, the value of this parameter is nil.

activityError
An error object if the activity failed to complete, or nil if the the activity completed normally.
Comment: possibly what I'm after??????

So is a minor embellishment of the B4i ActivityViewController wrapper all that is required?

Any help appreciated...
 
Upvote 0

Semen Matusovskiy

Well-Known Member
Licensed User
You can set own CompletionWithItemsHandler. For example, after avc.Show (...) call OBJC funcion
B4X:
    Dim noMe As NativeObject = Me
    noMe.RunMethod ("setCH:", Array (avc))

Simpliest OBJC-function (how to transfer results from OBJC to B4i is described in many topics)

B4X:
#If OBJC
- (void) setCH: (UIActivityViewController *) avc {
   [avc setCompletionWithItemsHandler: ^(NSString * __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError)
      {
      NSLog(@"completed : %d", completed);
      NSLog (@"activityType : %@", activityType);
      NSLog (@"activityError : %@", activityError);          
      }
   ]; }
#End If

Note, avc_Complete will not work, because we changed completionHandler.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Semen,

Thanks for your response - I was able to insert your suggestion in my code and got it working.

Problem is that when I get it to fail as indicated in post #1 the activityError is null - not sure whether this means I have done something wrong or this is not the way to get the error message (viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted})
 
Upvote 0

Semen Matusovskiy

Well-Known Member
Licensed User
If to search by UIViewServiceInterfaceErrorDomain Code=3, it's possible to find some posts with similar problem. But I did not notice a solution.
Looks like IOS bug. I can try to reproduce on my iPhone / Simulator. But I am not sure that an experiment will be correct. Can you describe, where do you run (iphone/simulator, OS release), memory size and a size of image.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Semen, I will try to knock up a example that generates the error message in the next day or so.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Semen,

Please find attached a totally stripped down version of my app that just demonstrates generation of the message:

viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}

You need to fill in Project > Build Configurations and the stuff at the top of Main.

I haven't put in your OBJC code.

If you just launch it in Debug mode it should show the UIActivityViewController pop-up.

On my device there is an app called "Notes" - I can cause it to generate the message when I try to share to this app.

Interestingly the file in DirAssets (bigredsquare.jpg) I had to make significantly larger than the equivalent file when running my full app - so I'm guessing the problem is memory related.

If it works properly on your device (i.e. you get "Success True" in the log) I would suggest making bigredsquare.jpg bigger until it fails.

Thanks in advance for any suggestions/solutions you come up with...
 

Attachments

  • Test.zip
    5.1 KB · Views: 294
Upvote 0

Semen Matusovskiy

Well-Known Member
Licensed User
Well, I see a problem. I took not a very huge file (about 7 MB) and see strange behaviour not in Notes only. I will make experiments. Doubt that a problem is in memory as it is.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
I took not a very huge file (about 7 MB)
Semen, my experience is that the image "size" that is critical seems to be pixels wide x pixels height NOT file size - probably because the operation is happening on bitmaps (just a guess).
 
Upvote 0

Semen Matusovskiy

Well-Known Member
Licensed User
I was able to add bitmap 25 MB (in release mode). But this looks as near limit.
Probably, better to share a file (CreateFileUrl (...)) than bitmap.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Semen,

My problem is not fixing the issue but detecting when it happens so I can give the user the option of scaling the image and retrying.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Semen,

To my limited knowledge so any correction is welcome:

The trouble with iOS photos is they are stored in the photo album, by default, in HEIC format - the user can change this to jpg but this is not within the reach of my (or any other?) app.

The problem with HEIC is that it has proved to be a format with limited adoption by others - and you don't know what format/s the app you are sharing with will accept. Or more correctly you can limit the range of apps you can share to by specifying (say) jpg.

Also, if I wanted to restore the photo to jpg I have an additional problem - what was the original jpg compression?

To avoid these sorts of issues I decided to share photos as bitmaps - the lowest common denominator.

An interception of console messages is not a simple task.
I appreciate your time and effort here - I can live without knowing precisely why a share attempt failed.

My workaround involves a mechanism so that when a share failure is detected the user is given a dialog:

Untitled.png


He can then reduce by 10%/20%/... and retry or quit.

The only problem with this is that it will be triggered by either the user cancelling the share OR the share failing (and generating the notorious log message).

If it is generated because the user cancelled the share then it is a bit clunky.

Thanks again...
 
Upvote 0
Top