Can I save data to an App Group container from a ILClassificationRequest classifier?

Title's basically the whole question. I'm writing an SMS/Call Reporting extension (ILClassificationUIExtensionViewController). My goal is to keep everything on device and not use the built-in SMS/network reporting. To that end, I'm trying to write to a file in the App Group container from the classificationResponse handler. I'm getting Error 513: "You don’t have permission to save the file “classification_log.txt” in the [app group container folder]".

I haven't been able to find much in the documentation on whether this behavior is enforced in classificationResponse handlers. Apple's barebones page on "SMS and Call Spam Reporting"[1] says "the system always deletes your extension’s container after your extension terminates," but that doesn't answer whether you can write to an App Group container. I haven't been able to find that answer elsewhere. ChatGPT and Gemini are both very sure it can be done. Any thoughts?

[1] https://developer.apple.com/documentation/identitylookup/sms-and-call-spam-reporting

Answered by DTS Engineer in 860436022

I haven't been able to find much in the documentation on whether this behavior is enforced in classificationResponse handlers. Apple's barebones page on "SMS and Call Spam Reporting"[1] says "the system always deletes your extension’s container after your extension terminates," but that doesn't answer whether you can write to an App Group container.

No, you cannot.

This could have been more directly stated, but this is basically implementing one of the strongest possible restrictions* around your extension. For comparison, the filter data provider extension, which can examine the contents of "all" network traffic, is allowed to write to its data container but cannot write ANYWHERE else on the system (nor can its container be read). ILClassificationUIExtensionViewController takes that level of protection one step further and doesn't even preserve your app’s own container.

*We could have simply blocked writing, but I suspect container writing was allowed to provide a bit more implementation flexibility. For example, I believe you can read from your group container, so you could customize the interface you present by:

  • Copying a dynamic resource from your group container to your extension’s app container.

  • Writing to the resource to modify.

  • Displaying that modified resource.

Allowing writes also reduces "friction" when using other frameworks/libraries. For example, a library may require a read/write preference file, even though it doesn't actually NEED that functionality to "work". So we allow it to write, then throw the data away as soon as the extension exits.

I haven't been able to find that answer elsewhere.

I'm glad I was able to help.

ChatGPT and Gemini are both very sure it can be done. Any thoughts?

They're both wrong. Unfortunately, the problem with AI is that it's basically "making up" answers based on the information it was trained with. That works surprisingly well for many of our frameworks because:

  1. There's a lot of information "out there" about how our frameworks work.

  2. The behavior of our frameworks is consistent enough that "guessing" about how it works is often right.

Unfortunately, that approach falls apart if the technology is relatively "obscure" (so there isn't a lot of #1) and/or doesn't follow the "rules" (so #2 fails). Both of those issues apply here.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

I'm trying to write to a file

How!? By way of fileExporter(isPresented:document:contentType:defaultFilename:onCompletion:) ? If you use fileExporter and gets a permission error, that's most likely because you are not using the security-scoped bookmark.

I'm sorry for the bad advice. I got mixed up. You get the said permission error for .fileImporter, not .fileExporter.

Accepted Answer

I haven't been able to find much in the documentation on whether this behavior is enforced in classificationResponse handlers. Apple's barebones page on "SMS and Call Spam Reporting"[1] says "the system always deletes your extension’s container after your extension terminates," but that doesn't answer whether you can write to an App Group container.

No, you cannot.

This could have been more directly stated, but this is basically implementing one of the strongest possible restrictions* around your extension. For comparison, the filter data provider extension, which can examine the contents of "all" network traffic, is allowed to write to its data container but cannot write ANYWHERE else on the system (nor can its container be read). ILClassificationUIExtensionViewController takes that level of protection one step further and doesn't even preserve your app’s own container.

*We could have simply blocked writing, but I suspect container writing was allowed to provide a bit more implementation flexibility. For example, I believe you can read from your group container, so you could customize the interface you present by:

  • Copying a dynamic resource from your group container to your extension’s app container.

  • Writing to the resource to modify.

  • Displaying that modified resource.

Allowing writes also reduces "friction" when using other frameworks/libraries. For example, a library may require a read/write preference file, even though it doesn't actually NEED that functionality to "work". So we allow it to write, then throw the data away as soon as the extension exits.

I haven't been able to find that answer elsewhere.

I'm glad I was able to help.

ChatGPT and Gemini are both very sure it can be done. Any thoughts?

They're both wrong. Unfortunately, the problem with AI is that it's basically "making up" answers based on the information it was trained with. That works surprisingly well for many of our frameworks because:

  1. There's a lot of information "out there" about how our frameworks work.

  2. The behavior of our frameworks is consistent enough that "guessing" about how it works is often right.

Unfortunately, that approach falls apart if the technology is relatively "obscure" (so there isn't a lot of #1) and/or doesn't follow the "rules" (so #2 fails). Both of those issues apply here.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks very much, Kevin. It does seem like a bit of a miss that you can send the data off-device to train a filter, but can't do so on-device, especially given all the new on-device ML support. Perhaps there's a good reason for it, but if not, I'd love to be able to do this in a future version.

Best, Athul

Thanks very much, Kevin. It does seem like a bit of a miss that you can send the data off-device to train a filter, but can't do so on-device, especially given all the new on-device ML support. Perhaps there's a good reason for it.

The issue here is that, for obvious reasons, the user’s message data is considered particularly sensitive. Sending it off-device is obviously a serious concern, but if that's going to happen, the best way to mitigate that is by minimizing the ability to relate messages to each other... and the best way to ensure that is to ensure that the extension doesn't have "any" content to relate or share.

That leads to here:

but if not, I'd love to be able to do this in a future version.

I don't know if it's feasible or not, but if you're willing to commit being ENTIRELY on-device, the obvious alternative here would be to allow you to store data but completely disable all network access. If that's an approach you'd be interested in implementing, then I'd recommend filing a bug asking for that alternative. I can't promise it will happen, but I do think it could be an interesting option.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Can I save data to an App Group container from a ILClassificationRequest classifier?
 
 
Q