Explore the integration of web technologies within your app. Discuss building web-based apps, leveraging Safari functionalities, and integrating with web services.

All subtopics

Post

Replies

Boosts

Views

Activity

I am unable to debug a Safari extension in Xcode 16 beta 1 on iOS 18 beta
The process to reproduce: Create a new extension with Xcode 16 beta. Run it on the simulator or any iOS device with iOS 18 beta installed. Open Safari on your Mac, then open Develop -> Device you use. Unable to access these menus for iOS 18: 1. Extension - Extension Background Content 2. Extension - Extension Pop-up Page - popup.html However, for iOS 17.4, I can see these options in Develop -> Device iOS(17.4). I have another extension on the App Store that is not working on the iOS 18 beta, but I am unable to debug it because of this issue.
1
0
254
2w
Microphone input in website in webview for swiftui
I have a website of a chatbot that also accepts microphone inputs and I embedded that into my swift and the everything other than the mic is working. I have included permission in the info file and here’s some of the code : import SwiftUI import WebKit import AVFoundation struct WebView: UIViewRepresentable { let url: URL class Coordinator: NSObject, WKUIDelegate, WKNavigationDelegate { var parent: WebView init(parent: WebView) { self.parent = parent } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { decisionHandler(.allow) } func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in completionHandler() })) parent.presentAlert(alert: alert) } func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in completionHandler(true) })) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in completionHandler(false) })) parent.presentAlert(alert: alert) } func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { let alert = UIAlertController(title: prompt, message: nil, preferredStyle: .alert) alert.addTextField { textField in textField.text = defaultText } alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in completionHandler(alert.textFields?.first?.text) })) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in completionHandler(nil) })) parent.presentAlert(alert: alert) } func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) { decisionHandler(.grant) } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { print("Navigation error: \(error.localizedDescription)") } } func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIView(context: Context) -> WKWebView { let webConfiguration = WKWebViewConfiguration() webConfiguration.allowsInlineMediaPlayback = true webConfiguration.mediaTypesRequiringUserActionForPlayback = [] let webView = WKWebView(frame: .zero, configuration: webConfiguration) webView.uiDelegate = context.coordinator webView.navigationDelegate = context.coordinator requestMicrophoneAccess() return webView } func updateUIView(_ webView: WKWebView, context: Context) { let request = URLRequest(url: url) webView.load(request) } func requestMicrophoneAccess() { AVAudioSession.sharedInstance().requestRecordPermission { granted in DispatchQueue.main.async { if granted { print("Microphone access granted") } else { print("Microphone access denied") } } } } func presentAlert(alert: UIAlertController) { if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let rootViewController = windowScene.windows.first?.rootViewController { rootViewController.present(alert, animated: true, completion: nil) } } }
0
0
198
2w
Microphone input in website in webview for swiftui
I have a website of a chatbot that also accepts microphone inputs and I embedded that into my swift and the everything other than the mic is working. I have included permission in the info file and here's some of the code : import SwiftUI import WebKit import AVFoundation struct WebView: UIViewRepresentable { let url: URL class Coordinator: NSObject, WKUIDelegate, WKNavigationDelegate { var parent: WebView init(parent: WebView) { self.parent = parent } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { decisionHandler(.allow) } func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in completionHandler() })) parent.presentAlert(alert: alert) } func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in completionHandler(true) })) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in completionHandler(false) })) parent.presentAlert(alert: alert) } func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { let alert = UIAlertController(title: prompt, message: nil, preferredStyle: .alert) alert.addTextField { textField in textField.text = defaultText } alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in completionHandler(alert.textFields?.first?.text) })) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in completionHandler(nil) })) parent.presentAlert(alert: alert) } func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) { decisionHandler(.grant) } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { print("Navigation error: \(error.localizedDescription)") } } func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIView(context: Context) -> WKWebView { let webConfiguration = WKWebViewConfiguration() webConfiguration.allowsInlineMediaPlayback = true webConfiguration.mediaTypesRequiringUserActionForPlayback = [] let webView = WKWebView(frame: .zero, configuration: webConfiguration) webView.uiDelegate = context.coordinator webView.navigationDelegate = context.coordinator requestMicrophoneAccess() return webView } func updateUIView(_ webView: WKWebView, context: Context) { let request = URLRequest(url: url) webView.load(request) } func requestMicrophoneAccess() { AVAudioSession.sharedInstance().requestRecordPermission { granted in DispatchQueue.main.async { if granted { print("Microphone access granted") } else { print("Microphone access denied") } } } } func presentAlert(alert: UIAlertController) { if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let rootViewController = windowScene.windows.first?.rootViewController { rootViewController.present(alert, animated: true, completion: nil) } } }
0
0
167
2w
Cannot navigate to external webpages from internal extension pages
In iOS 18, internal extension pages cannot navigate to external webpages, either via href links or through JS methods such as window.location.replace. Nothing happens when you try to navigate to an external webpage. Only other internal pages can be navigated to. This wasn't an issue on previous versions of iOS. It would be appreciated if this can be fixed as soon as possible. Feedback ID: FB14194963
2
1
293
2w
Undocumented changes in WebKit API in Xcode 16 break apps
Be warned! When developing your app in Xcode 16 be careful!!! The new SDK has changes that cause builds on Xcode Cloud and other non-beta Xcode to have bugs (EVEN WITH IOS TARGET SET LOWER). This wasted 2 days of development time, but in WKNavigationDelegate, the webView(_:decidePolicyFor:decisionHandler:) method has a new type signature that will ONLY work in the latest SDK. The change was that the decisionHandler now has a @MainActor attribute. This causes Swift to recognize that it "almost" meets an optional requirement and suggests that you change it. If you change it, it will cause builds to not include the optional method.
0
0
227
2w
App Crashes when loading webview " *** Assertion failure in -[UIApplication _performAfterCATransactionCommitsWithLegacyRunloopObserverBasedTiming:block:]"
In my app I am trying to load webview with an URL , I am checking is it loading on main thread also loading webview in main thread using DispatchQueue.main.async { self.loadRequest() } , webview loads successfully, then showing below error app crashes , unable to find the reason. "*** Assertion failure in -[UIApplication _performAfterCATransactionCommitsWithLegacyRunloopObserverBasedTiming:block:]" Thanks in advance
1
0
190
2w
HTTP requests timing out...
I am new to swift, so any advice would be appreciated. So the I have seen URL and URLSession return a timeout response, the android varient of my app does not show this issue. class HasInternet: ObservableObject { let monitor = NWPathMonitor() let queue = DispatchQueue(label: "Monitor") private var status: NWPath.Status = .requiresConnection @Published var isConnected = false init(){ monitor.pathUpdateHandler = { [weak self] path in if let url = URL(string: "https://google.com") { var request = URLRequest(url: url) request.httpMethod = "HEAD" request.timeoutInterval = 30 let sessionConfig = URLSessionConfiguration.default sessionConfig.timeoutIntervalForRequest = 30.0 sessionConfig.timeoutIntervalForResource = 60.0 URLSession(configuration: sessionConfig) .dataTask(with: request) { (_, response, error) -> Void in guard error == nil else { return } guard (response as? HTTPURLResponse)? .statusCode == 200 else { return } DispatchQueue.main.async { self?.isConnected = true } } .resume() } } monitor.start(queue: queue) } } Here is another place with the same behaviour. func post(dModel: DialogModel? = nil, url: String, type: responseTypes, body: [String: Any], headers: [headerType], async: Bool = true) { //async let semaphore = DispatchSemaphore(value: 0) let timeout: TimeInterval = 10 if let url = URL(string: url) { var request = URLRequest(url: url) request.httpMethod = "POST" request.timeoutInterval = 30 for header in headers { request.setValue(header.value, forHTTPHeaderField: header.key) } do { request.httpBody = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted) } catch let error { self.processError(dModel: dModel, error: error.localizedDescription, type: .report) return } let sessionConfig = URLSessionConfiguration.default sessionConfig.timeoutIntervalForRequest = 30.0 sessionConfig.timeoutIntervalForResource = 60.0 URLSession(configuration: sessionConfig) .dataTask(with: request) { (data, response, error) -> Void in if let error = error { self.processError(dModel: dModel, error: error.localizedDescription, type: .report) if(async){ semaphore.signal() // Signal semaphore even in case of error } return } if let httpResponse = response as? HTTPURLResponse{ if let unWrappedData = data { if let httpResponseData = String(data: unWrappedData, encoding: .utf8) { self.parse(dModel: dModel, type: type, response: httpResponseData, statusCode: httpResponse.statusCode) } } } else { self.processError(error: "Invalid response") } if(async){ semaphore.signal() // Signal semaphore after processing the response } } .resume() if(async){ semaphore.wait(timeout: .now() + timeout) } } else { processError(error: "Invalid URL") } }
0
0
151
2w
how can i get camera access in ios12 application embedded html
i can sure the app already hava the camera access, but in the embedded html, i still cannot open the camera. And this HTML page is work at Safari, but cant work on app when the page is embedded in app. there is the error message: DOMException: undefine is not an object (evaluating 'navigator.mediaDevices.getUserMedia') and i also try to use 'navigator.getUserMedia' and 'navigator.mediaDevices.enumerateDevices()', this all dont work.
0
0
206
2w
IPhone browser copy failed on page H5
codes: const el = document.createElement('textarea'); document.body.appendChild(el); el.value = 'copy text'; el.readOnly = true; el.focus = true; el.select(); const res = document.execCommand('copy') if (res) { alert('success') } else { alert('fail') }
0
0
152
2w
Web Extensions's background page is missing in the Develop -> Web Extension Background Content menu in the latest Safari Technology Preview
Hello! I was wondering if any other developers are experiencing issues with accessing the web extension background script console, sources, etc. on the latest Safari Technology preview or macOS Sequoia betas. We have an extension which has a persistent background script. In the latest public release of Safari version 17.5 (19618.2.12.11.6) on macOS Sonoma, everything works as expected. When I enable developer mode in Safari, it shows an additional "Develop" menu and when I select "Web Extension Background Content" in the dropdown, it shows a list of background pages for all installed extensions. Attaching a screenshot for reference. However, if I install the latest Safari Technology Preview 197 on macOS Sonoma or just test with the Safari version that comes with MacOS Sequoia beta 1 or beta 2, the "Web Extension Background Content" dropdown menu does not list any background pages. Attaching a screenshot for reference. We started discussing the issue with Apple during the latest WWDC. If anyone at Apple sees this post, I opened FB13834388 to track this issue. However according to Apple, they cannot reproduce the issue exactly as I see it on all macOS machines around me including clean virtual machines, real hardware (MacBook Pro M1 Max, MacBook Air M2, MacBook Pro Intel based). The "Web Extension Background Content" menu looks as expected on their end which is very confusing to me... I have a reason to believe that new Safari's developer tools are simply broken in the latest release. I base that statement on the fact that I cannot access it in case of our own Safari extension, Apple's sample "Sea Creator" extension and a few random extensions that I got from the App Store. I was wondering if anyone else can observe the same behavior or all machines around me are haunted :) Please share if you have similar issues with Safari Technology Preview 197 or Safari on the latest macOS Sequoia beta. Any feedback is important to us. If it's a widespread issue, then Apple should prioritize is accordingly. If the issue is somehow specific to our testing, we will fix it on our side. But any test results at this point are bringing more clarity to the situation and are highly appreciated.
2
0
290
2w
ERR_NETWORK_CHANGED
Your connection was interrupted. A network change was detected. ERR_NETWORK_CHANGED This started to happen on my Chrome/Brave Browser just after I updated my MacOS to developer beta (Version 15.0 Beta (24A5279h)).
1
0
212
3w
Safari Tabs in shared Tabgroups multiplied
As I wanted to transfer my existing tabgoups from my iPhone/Mac to my new iPad (strange that it’s not working on its own) I shared the tabgroup as a message and opened it on my iPad. From that moment on I had shared tabgroups with a blue dot behind the individual tabs in the tabgroups and a menu bar on the top of each tab where I was able to discontinue the sharing. After a short while a noticed all tabs in the tab groups consisting of more than 400 tabs multiplied 5x. I am using iOS 18 beta on the iPad and iOS 17.6 on my iPhone. My MacBook Pro from 2016 wasn’t used during the sharing process, but after the Desaster started I disabled tab groups on safari settings in hopes of conserving the tab group without the multiplies on my MacBook. On my MacBook i opened safari and clicked on the shared Tabgroups whereat a warning poped up that MacOsx 13 or later is required for using shared tabgroups nonetheless all tabs are multiplied… please help 😀
0
0
196
3w
Safari Extension Service Worker Permanently Killed on iOS 17.4.x-17.6
Since probably the late iOS 17.4.x, 17.5.1 and still now in 17.6 beta our extension has been experiencing issues with the accompanying background script or service worker being permanently killed with no warning after about 30-45 seconds after initial installation (installation, not page load!). In all other browsers (including Safari on MacOS) unloading the service worker is part of the normal lifecycle to save memory and CPU if it is idle. In our extension the service worker is used only during the first 5-10 seconds of every page visit, so we are used to seeing it unload after that and consider this a good thing. However, normally, the service worker is able to wake back up when needed - which is no longer the case in iOS. Once dead, nothing a normal user would do can wake the service worker back up: No events like webNavigation or similar will trigger anymore Any attempt to call sendMessage to it from a content-script also does not wake up the service worker and instead returns undefined to the content script immediately Closing and opening Safari does not start it again The only two things that will give the service worker another 30-40 seconds of life is a reboot of the device or disabling and then re-enabling the extension. During those few second the extension is working perfectly. There are no errors or indications in the logs of what is going on and the extension works just fine in Chrome, Firefox, Edge as well as Safari on MacOS and Safari in the Mobile simulator. Only actual iOS devices fail. It seems like a temporary workaround is to change the manifest to not load the service worker as a service worker by changing "background": { "service_worker": "service.js" } to "background": { "scripts": ["service.js"], "persistent": false } With this change (courtesy of https://forums.developer.apple.com/forums/thread/721222) the service worker is still unloaded but correctly starts up again when needed. Having to make this change does not seem to be consistent with manifest v3 specs though (see this part in Chrome’s migration guide as an example: https://developer.chrome.com/docs/extensions/develop/migrate/to-service-workers#update-bg-field). According to the release notes of 17.6 beta this bug was supposedly fixed: “Fixed an issue where Safari Web Extension background pages would stop responding after about 30 seconds. (127681420)” However, this bug is not fixed - or at least not entirely fixed. It seems to work better for super simple tests doing nothing but pinging the service worker from the content script, but for the full blown extension there is no difference at all between 17.5.1 and 17.6. Has there been a change in policy about service workers and background scripts for Safari in iOS? Are anyone else seeing this issue? Also seemingly related: https://forums.developer.apple.com/forums/thread/756309 https://forums.developer.apple.com/forums/thread/750330 https://developer.apple.com/forums/thread/757926 https://forums.developer.apple.com/forums/thread/735307
3
3
359
3w