Is there any supported mechanism in Safari Web Extensions (MV3) for capturing or logging network request data (like fetch, XHR, or webRequest) triggered by the web page?
Extensions
RSS for tagGive users access to your app's functionality and content throughout iOS and macOS using extensions.
Posts under Extensions tag
200 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
My app is designed to share and import images with apps such as the File app. I created a program after looking at various information, but the app from which the images are shared does not work, and the screen cannot be moved to the main screen of my app. The program is as follows. How should I modify it?
import UIKit
import MobileCoreServices
import UniformTypeIdentifiers
class ShareViewController: UIViewController {
let suiteName: String = "group.com.valida.pettyGeneral"
let keyString: String = "share-general"
override func viewDidLoad() {
var nameArray: [String] = [String]()
let sharedDefaults: UserDefaults = UserDefaults(suiteName: self.suiteName)!
guard let inputItem = self.extensionContext?.inputItems.first as? NSExtensionItem, let attachments = inputItem.attachments else {
return
}
let identifier = UTType.image.identifier
let imgAttachments = attachments.filter { $0.hasItemConformingToTypeIdentifier(identifier) }
let dispatchGroup = DispatchGroup()
for (no, itemProvider) in imgAttachments.enumerated() {
dispatchGroup.enter()
itemProvider.loadItem(forTypeIdentifier: identifier, options: nil) { [self] item, error in
do {
if let error = error {
throw error
} else if let url = item as? URL {
let data = try Data(contentsOf: url)
let fileManager = FileManager.default
let url = fileManager.containerURL(forSecurityApplicationGroupIdentifier: suiteName)
if let url = url?.appendingPathComponent(String(no)) {
try! data.write(to: url)
}
nameArray.append(String(no))
}
do { dispatchGroup.leave() }
} catch {
print("Error")
do { dispatchGroup.leave() }
}
}
}
dispatchGroup.notify(queue: .main) { [self] in
// 全ての画像を保存
sharedDefaults.set(nameArray, forKey: self.keyString)
sharedDefaults.synchronize()
// メニュー画面に移動する
openUrl(url: URL(string: "container-general://"))
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
}
//#selector(openURL(_:))はこの関数がないと作れない
@objc func open(_ url: URL) {}
func openUrl(url: URL?) {
let selector = #selector(open(_ : ))
var responder = (self as UIResponder).next
while let r = responder, !r.responds(to: selector) {
responder = r.next
}
_ = responder?.perform(selector, with: url)
}
func openContainerApp() {
let url = URL(string: "container-general://") // カスタムスキームを作って指定する
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
let selector = sel_registerName("openURL:")
application.perform(selector, with: url)
break
}
responder = responder?.next
}
}
}
Hi
We have a non-replicated Files Provider extension on iOS that creates multiple domains. I've noticed that iOS typically creates one process per domain, so I would assume that each process is meant to handle one domain. However, in practice, is seems that calls for any domain can occur in any process.
I'm wondering whether there is supposed to be a mapping, implying there might be something wrong with the code, or whether we shouldn't make assumptions about domain:process mapping.
Thanks for any info you can provide.
When I use IOKit/usb/IOUSBLib to toggle build-in camera, I got an ERROR:ret IOReturn -536870210
How can I resolve it? Can I use IOUSBLib to disable or hide build-in camera?
My environment:
Model Name: MacBook Pro
ProductVersion: 15.5
Model Identifier: MacBookPro15,2
Processor Name: Quad-Core Intel Core i5
Processor Speed: 2.4 GHz
Number of Processors: 1
// 禁用/启用USB设备
bool toggleUSBDevice(uint16_t vendorID, uint16_t productID, bool enable) {
std::cout << (enable ? "Enabling" : "Disabling") << " USB device with VID: 0x"
<< std::hex << vendorID << ", PID: 0x" << productID << std::endl;
// 创建匹配字典查找指定VID/PID的USB设备
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
if (!matchingDict) {
std::cerr << "Failed to create USB device matching dictionary." << std::endl;
return false;
}
// 设置VID/PID匹配条件
CFNumberRef vendorIDRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt16Type, &vendorID);
CFNumberRef productIDRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt16Type, &productID);
CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), vendorIDRef);
CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), productIDRef);
CFRelease(vendorIDRef);
CFRelease(productIDRef);
// 获取匹配的设备迭代器
io_iterator_t deviceIterator;
if (IOServiceGetMatchingServices(kIOMainPortDefault, matchingDict, &deviceIterator) != KERN_SUCCESS) {
std::cerr << "Failed to get USB device iterator." << std::endl;
CFRelease(matchingDict);
return false;
}
io_service_t usbDevice;
bool result = false;
int deviceCount = 0;
// 遍历所有匹配的设备
while ((usbDevice = IOIteratorNext(deviceIterator)) != IO_OBJECT_NULL) {
deviceCount++;
// 获取设备路径
char path[1024];
if (IORegistryEntryGetPath(usbDevice, kIOServicePlane, path) == KERN_SUCCESS) {
std::cout << "Found device at path: " << path << std::endl;
}
// 打开设备
IOCFPlugInInterface** plugInInterface = NULL;
IOUSBDeviceInterface** deviceInterface = NULL;
SInt32 score;
IOReturn ret = IOCreatePlugInInterfaceForService(
usbDevice,
kIOUSBDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugInInterface,
&score);
if (ret == kIOReturnSuccess && plugInInterface) {
ret = (*plugInInterface)->QueryInterface(plugInInterface,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
(LPVOID*)&deviceInterface);
(*plugInInterface)->Release(plugInInterface);
}
if (ret != kIOReturnSuccess) {
std::cerr << "Failed to open USB device interface. Error:" << ret << std::endl;
IOObjectRelease(usbDevice);
continue;
}
// 禁用/启用设备
if (enable) {
// 启用设备 - 重新配置设备
ret = (*deviceInterface)->USBDeviceReEnumerate(deviceInterface, 0);
if (ret == kIOReturnSuccess) {
std::cout << "Device enabled successfully." << std::endl;
result = true;
} else {
std::cerr << "Failed to enable device. Error: " << ret << std::endl;
}
} else {
// 禁用设备 - 断开设备连接
ret = (*deviceInterface)->USBDeviceClose(deviceInterface);
if (ret == kIOReturnSuccess) {
std::cout << "Device disabled successfully." << std::endl;
result = true;
} else {
std::cerr << "Failed to disable device. Error: " << ret << std::endl;
}
}
// 关闭设备接口
(*deviceInterface)->Release(deviceInterface);
IOObjectRelease(usbDevice);
}
IOObjectRelease(deviceIterator);
if (deviceCount == 0) {
std::cerr << "No device found with specified VID/PID." << std::endl;
return false;
}
return result;
}
I'm currently trying the traditional mode on the latest beta and the slide-over and the traditional splitview is not available, I would like to ask if it's completely removed or just a minor bug because my automation app rely heavily on this old two feature
Hello everyone,
I’ve been trying to pass a URL from Safari (or any other app) into my own app via iOS extensions (similar to how if you go to a website, open the share sheet, and hit the ChatGPT app icon, it opens ChatGPT and pastes the website URL into the chat textbox), and I’m hitting a wall. I’ve attempted both a Share Extension (using SLComposeServiceViewController) and a UI-less Action Extension (using extensionContext?.open(...)), but in both scenarios, my main app never opens.
Here’s a summary of my setup:
Main App Target plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.elislothower.URLDisplayApp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array/>
</dict>
</plist>
This means my custom URL scheme is myapp://.
My app delegate (or SwiftUI’s .onOpenURL) correctly handles myapp://share?url=... if I open it directly from Safari.
Share Extension Attempt
Subclassed SLComposeServiceViewController.
Plist had com.apple.share-services as the NSExtensionPointIdentifier.
I called extensionContext?.open(deepLink) with myapp://share?url=..., but it always returned false.
Also, the UI (with Cancel/Post buttons) was overkill for my needs.
UI-less Action Extension Attempt
Created a no-UI action extension with com.apple.ui-services as NSExtensionPointIdentifier.
In my custom ActionViewController, I formed the same myapp://share?url=... deep link and called extensionContext?.open(deepLink).
The extension does appear in the share sheet, but again, open(deepLink) returns false—my main app never opens.
Confirmed Setup
I’ve tested the URL scheme in Safari: typing myapp://share?url=... directly prompts to open my app, and the URL is handled fine there.
I’ve ensured both extension Info.plists have <key>LSApplicationQueriesSchemes</key><array><string>myapp</string></array> so they can attempt to open that scheme.
Tried on both simulator and physical device. On the physical device, the main app is definitely installed and has been launched at least once.
Current Behavior
The extension logs that it forms the deep link (myapp://share?url=...) correctly.
extensionContext?.open(deepLink) fails (success == false), so the main app never opens.
I’ve also tried forcing the call on the main thread, simplifying the URL (like myapp://test), and checking for any typos or case-sensitivity issues—still no luck.
Is there a known iOS restriction or trick for allowing an extension (share or action) to open its containing app directly? Have I missed a configuration step or entitlement that’s necessary? Is it possible that iOS is just rejecting the call in these contexts?
I’d love any insight or suggestions from those who have successfully launched their main app from an extension. Thank you in advance!
ContentView.swift
Info.plist
URLDisplayAppApp.swift
URLDisplayApp.entitlements
ActionRequestHandler.swift
ActionViewController.swift
Info.plist
MyAppActionExtension.entitlements
I recently started building an iMessage game, and whenever I try to send the game through the first contact on the simulator to loop back into the second one, I get an alert saying "Unable to send. The recipient can not receive this item via satellite". Has anyone experienced this? If so, do you have a solution? It is making it a bit difficult to test the flow of my app.
I created a ShieldConfigurationExtension in Xcode 14.3 with File > New > Target > ShieldConfigurationExtension. This created the extension with all the necessary Info.plist values (correct NSExtensionPrincipalClass, etc.), with the extension included in embedded content in the host app target.
No matter what I try, the extension is not getting invoked when I shield applications from my host app. The custom UI does not show as the shield, and looking at the debugger, an extension process is never invoked.
I am shielding categories like this:
let managedSettings = ManagedSettingsStore()
...
managedSettings.shield.applicationCategories = .all()
And my extension code overrides all the ShieldConfigurationDataSource functions.
class ShieldConfigurationExtension: ShieldConfigurationDataSource {
override func configuration(shielding application: Application) -> ShieldConfiguration {
return ShieldConfiguration(
backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,
backgroundColor: UIColor.white,
icon: UIImage(systemName: "stopwatch"),
title: ShieldConfiguration.Label(text: "You are in a Present Session", color: .yellow)
)
}
override func configuration(shielding application: Application, in category: ActivityCategory) -> ShieldConfiguration {
return ShieldConfiguration(
backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,
backgroundColor: UIColor.white,
icon: UIImage(systemName: "stopwatch"),
title: ShieldConfiguration.Label(text: "You are in a Present Session", color: .yellow)
)
}
override func configuration(shielding webDomain: WebDomain) -> ShieldConfiguration {
return ShieldConfiguration(
backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,
backgroundColor: UIColor.white,
icon: UIImage(systemName: "stopwatch"),
title: ShieldConfiguration.Label(text: "You are in a Present Session", color: .yellow)
)
}
override func configuration(shielding webDomain: WebDomain, in category: ActivityCategory) -> ShieldConfiguration {
return ShieldConfiguration(
backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,
backgroundColor: UIColor.white,
icon: UIImage(systemName: "stopwatch"),
title: ShieldConfiguration.Label(text: "You are in a Present Session", color: .yellow)
)
}
}
What am I missing?
Topic:
App & System Services
SubTopic:
General
Tags:
Extensions
Managed Settings
Family Controls
Device Activity
There is an inconsistent issue when views are rendered from the Device Activity Report Extension. This issue is noticeable only on release versions and it works fine in debug mode.
Around 80% of the times, the Report Views return blank screen and this is only the case when a weekly/monthly filter is used. Although, it works as expected for daily report views.
My questions are:
How are all the Report Activity Views working fine in debug mode but not in release mode?
How the daily activity filter works fine in the release mode but the weekly/monthly filters don't work? Is this because of a memory limit issue in the extension?
As of now, I have the family-controls(distribution) entitlement only for the app and for the extensions I only have family-controls(development) entitlement. Do I need to request for family-controls(Distribution) entitlement even for the extensions?
I have seen threads on the forum mentioning the blank screen issue associated with the DeviceActivityReport but haven't found a solution to it. Any suggestions/feedback would be of great help, thanks.
Topic:
App & System Services
SubTopic:
General
Tags:
Extensions
Entitlements
Device Activity
Screen Time
I'm working on enabling a content filter in my iOS app using NEFilterManager and NEFilterProviderConfiguration. The setup works perfectly in debug builds when running via Xcode, but fails on TestFlight builds with the following error:
**Failed to save filter settings: permission denied
**
**Here is my current implementation:
**
(void)startContentFilter {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults synchronize];
[[NEFilterManager sharedManager] loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(@"Failed to load filter: %@", error.localizedDescription);
[self showAlertWithTitle:@"Error" message:[NSString stringWithFormat:@"Failed to load content filter: %@", error.localizedDescription]];
return;
}
NEFilterProviderConfiguration *filterConfig = [[NEFilterProviderConfiguration alloc] init];
filterConfig.filterSockets = YES;
filterConfig.filterBrowsers = YES;
NEFilterManager *manager = [NEFilterManager sharedManager];
manager.providerConfiguration = filterConfig;
manager.enabled = YES;
[manager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(@"Failed to save filter settings: %@", error.localizedDescription);
[self showAlertWithTitle:@"Error" message:[NSString stringWithFormat:@"Failed to save filter settings: %@", error.localizedDescription]];
} else {
NSLog(@"Content filter enabled successfully!");
[self showAlertWithTitle:@"Success" message:@"Content filter enabled successfully!"];
}
});
}];
});
}];
}
**What I've tried:
**
Ensured the com.apple.developer.networking.networkextension entitlement is set in both the app and system extension.
The Network extension target includes content-filter-provider.
Tested only on physical devices.
App works in development build, but not from TestFlight.
**My questions: **
Why does saveToPreferencesWithCompletionHandler fail with “permission denied” on TestFlight?
Are there special entitlements required for using NEFilterManager in production/TestFlight builds?
Is MDM (Mobile Device Management) required to deploy apps using content filters?
Has anyone successfully implemented NEFilterProviderConfiguration in production, and if so, how?
Topic:
App & System Services
SubTopic:
Networking
Tags:
Extensions
Swift
Network Extension
Objective-C
Hello All, I see an issue while running the Notification content Extension on simulator without checking the "Copy only when installing in app target -> Build Phases -> Embed App Extensions"
If I check "Copy only when installing in app target" then only it is working.
Can someone please confirm if Notification Content Extension is working on simulator. If yes how can we do that. Please share the details
As with the adoption of MV3 standards among all major browser vendors that allow browser extensions at the client-side, I understand that this is the same with Safari as well, as mentioned here (https://www.wwdcnotes.com/notes/wwdc22/10099/). However, as with Firefox, browsers may choose to adopt them incompletely and with few changes. I had a few questions regarding how Safari views this transition and what would be the next steps from here.
Thus, it would be really great if the browser team could provide your insights on any or all of the following points:
Would Safari adopt the exact standards proposed by the Chromium ecosystem such as with functionalities like header-based modifications in the coming days.
What would be the general timeline be for this in general?
Does this also translate to the fact that existing standards with MV2 standards would not be allowed to operate any further, as with the timeline with Chromium?
Regards
We have a setup where the system uses proxy settings configured via a PAC file. We are investigating how NWConnection behaves inside a Network Extension (NETransparentProxyProvider) with a transparent proxy configuration based on this PAC file.
Scenario:
The browser makes a connection which the PAC file resolves as "DIRECT" (bypassing the proxy)
Our Network Extension intercepts this traffic for analysis
The extension creates a new connection using NWConnection to the original remote address.
The issue: despite the PAC file’s "DIRECT" decision, NWConnection still respects the system proxy settings and routes the connection through the proxy.
Our questions:
Is it correct that NWConnection always uses the system proxy if configured ?
Does setting preferNoProxies = true guarantee bypassing the system proxy?
Additionally:
Whitelisting IPs in the Network Extension to avoid interception is not a viable solution because IPs may correspond to multiple services, and the extension only sees IP addresses, not domains (e.g., we want to skip scanning meet.google.com traffic but still scan other Google services on the same IP range).
Are there any recommended approaches or best practices to ensure that connections initiated from a Network Extension can truly bypass the proxy (for example, for specific IP ranges or domains)?
we have written a QL preview generator for some 3D data formats not supported by the AR Quicklook generators included in iOS.
however, we are struggeling with the 100 MB memory ceiling imposed on an app extension in iOS.
we have included the "Increased Memory Limit" entitlement in both the app and in the preview extensions.
nevertheless, the preview generator is limited to 100 MB, even on most recent devices like iPhone 16 Pro Max. we can even see 100 MB limit when we attach to the process with Xcode.
my question: did we miss anything? are there additional steps necessary to obtain the increased memory limit? must we explicitly apply for it? 500 MB would be fine (our preview generator does not load textures).
best regards
I have an outside Mac App Store app. It has an action extension. I can't get it to run from Xcode. I try to debug it from Safari. It shows up in the menu when I click the 'rollover' button but it doesn't show up in the UI at all. Xcode doesn't give me any indication as to what the problem is. I see this logs out in console when I try to open the action extension:
Prompting policy for hardened runtime; service: kTCCServiceAppleEvents requires entitlement com.apple.security.automation.apple-events but it is missing for accessing={TCCDProcess: identifier=BundleIdForActionExtHere, pid=6650, auid=501, euid=501, binary_path=/Applications/AppNamehere.app/Contents/PlugIns/ActionExtension.appex/Contents/MacOS/ActionExtension}, requesting={TCCDProcess: identifier=com.apple.appleeventsd, pid=550, auid=55, euid=55, binary_path=/System/Library/CoreServices/appleeventsd},
I don't see why the Action extension needs Apple events but I added it to the entitlements anyway but it doesn't seem to matter. The action extension fails to open.
Hello everyone,
I’m working on an iOS app that uses the new DeviceActivity framework to monitor and report user screen‐time in an extension (DeviceActivityReportExtension). I need to persist my processed screen‐time data into a standalone SQLite database inside the extension, but I’m running into issues opening and writing to the database file.
Here’s what I’ve tried so far:
import UIKit
import DeviceActivity
import SQLite3
class DeviceActivityReportExtension: DeviceActivityReportExtension {
private var db: OpaquePointer?
override func didReceive(_ report: DeviceActivityReport) async {
// 1. Construct path in app container:
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.mycompany.myapp")
let dbURL = containerURL?.appendingPathComponent("ScreenTimeReports.db")
// 2. Open database:
if sqlite3_open(dbURL?.path, &db) != SQLITE_OK {
print("❌ Unable to open database at \(dbURL?.path ?? "unknown path")")
return
}
defer { sqlite3_close(db) }
// 3. Create table if needed:
let createSQL = """
CREATE TABLE IF NOT EXISTS reports (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT,
totalScreenTime DOUBLE
);
"""
if sqlite3_exec(db, createSQL, nil, nil, nil) != SQLITE_OK {
print("❌ Could not create table: \(String(cString: sqlite3_errmsg(db)))")
return
}
// 4. Insert data:
let insertSQL = "INSERT INTO reports (date, totalScreenTime) VALUES (?, ?);"
var stmt: OpaquePointer?
if sqlite3_prepare_v2(db, insertSQL, -1, &stmt, nil) == SQLITE_OK {
sqlite3_bind_text(stmt, 1, report.date.description, -1, nil)
sqlite3_bind_double(stmt, 2, report.totalActivityDuration)
if sqlite3_step(stmt) != SQLITE_DONE {
print("❌ Insert failed: \(String(cString: sqlite3_errmsg(db)))")
}
}
sqlite3_finalize(stmt)
}
}
However:
Path issues: The extension’s sandbox is separate from the app’s. I’m not sure if I can use the same App Group container, or if there’s a better location for an on‐extension database.
Entitlements: I’ve added the App Group (group.com.mycompany.myapp) to both the main app and the extension, but the file never appears, and I still get “unable to open database” errors.
My questions are:
How do I correctly construct a file URL for an SQLite file in a DeviceActivityReportExtension?
Is SQLite the recommended approach here, or is there a more “Apple-approved” pattern for writing data from a DeviceActivity extension?
Any sample code snippets, pointers to relevant Apple documentation, or alternative approaches would be greatly appreciated!
We have a Safari extension that's been up on the App Store for about 18 months with no apparent issues. This week, however, while working on an update, we uninstalled the production version on our test machines and installed a developer version. When we had some issues, we tried to go back to the production version downloaded from the App Store, but we get an pop saying "Unable to download App." In the log, the most obviously relevant error is 'Operation not permitted'.
This occurs on several machines and different logins on those machines in both norma and safe modes. However, on another machine that never had one installed, we could still install the app from the app store, so I suspect there is something left behind that needs to be removed, but I don't know what.
FWIW, I see the download directory getting created under /Applications, but it is promptly removed when the failure popup appears.
Any suggestions?
A message filter extension is only forwarded SMSs by the OS for filtering, iMessages aren't.
But what is the situation with RCS messages? Will they be filterable by a message filtering extension?
Hello,
In our application, we have implemented an app extension to allow users to open the main app directly from the share activity window. To achieve this, we used the openURL(:) method from the NSExtensionContext class, as documented here: openURL(:).
However, we received one post from Apple stating that opening the main app directly is typically only supported in extensions such as Today widgets or iMessage apps. They also mentioned that this approach may require an additional review during the App Store submission process.
Link: https://developer.apple.com/documentation/foundation/nsextensioncontext/1416791-openurl
Could someone clarify:
If using openURL(_:) in a share extension to open the main app would lead to potential issues during App Store submission?
Are there specific guidelines or alternative approaches we should follow to ensure compliance?
Any insights or recommendations would be greatly appreciated.
Thank you!
Topic:
App & System Services
SubTopic:
General
Tags:
Mobile Core Services
Developer Tools
Extensions
When our Safari Web Extension makes a api request from its background script (registered via "scripts" in manifest.json, e.g., "background": { "scripts": ["js/background.bundle.js"] }) to our authenticated API endpoint (https://api-domain/user), the Cookie header is not included in the request. This occurs only when the extension is running within a non-default Safari User Profile. This causes our API to treat the user as unauthenticated. The exact same extension code, manifest, and API call work correctly (Cookie header is present and user is authenticated) when the extension is running in the Default Safari User Profile.