@capgo/inappbrowser 6.11.1 → 6.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +50 -42
  2. package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +161 -41
  3. package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +83 -22
  4. package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewCallbacks.java +2 -0
  5. package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +749 -96
  6. package/android/src/main/res/drawable/ic_share.xml +10 -0
  7. package/android/src/main/res/layout/activity_browser.xml +8 -0
  8. package/android/src/main/res/layout/content_browser.xml +10 -1
  9. package/android/src/main/res/layout/tool_bar.xml +19 -7
  10. package/android/src/main/res/values/strings.xml +2 -0
  11. package/android/src/main/res/values/themes.xml +27 -0
  12. package/dist/docs.json +211 -37
  13. package/dist/esm/definitions.d.ts +244 -31
  14. package/dist/esm/definitions.js +12 -1
  15. package/dist/esm/definitions.js.map +1 -1
  16. package/dist/plugin.cjs.js +12 -1
  17. package/dist/plugin.cjs.js.map +1 -1
  18. package/dist/plugin.js +12 -1
  19. package/dist/plugin.js.map +1 -1
  20. package/ios/Plugin/InAppBrowserPlugin.swift +344 -44
  21. package/ios/Plugin/WKWebViewController.swift +499 -45
  22. package/package.json +7 -8
  23. package/ios/Plugin/Assets.xcassets/Back.imageset/Back.png +0 -0
  24. package/ios/Plugin/Assets.xcassets/Back.imageset/Back@2x.png +0 -0
  25. package/ios/Plugin/Assets.xcassets/Back.imageset/Back@3x.png +0 -0
  26. package/ios/Plugin/Assets.xcassets/Back.imageset/Contents.json +0 -26
  27. package/ios/Plugin/Assets.xcassets/Forward.imageset/Contents.json +0 -26
  28. package/ios/Plugin/Assets.xcassets/Forward.imageset/Forward.png +0 -0
  29. package/ios/Plugin/Assets.xcassets/Forward.imageset/Forward@2x.png +0 -0
  30. package/ios/Plugin/Assets.xcassets/Forward.imageset/Forward@3x.png +0 -0
@@ -46,6 +46,10 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
46
46
  var currentPluginCall: CAPPluginCall?
47
47
  var isPresentAfterPageLoad = false
48
48
  var webViewController: WKWebViewController?
49
+ private var closeModalTitle: String?
50
+ private var closeModalDescription: String?
51
+ private var closeModalOk: String?
52
+ private var closeModalCancel: String?
49
53
 
50
54
  private func setup() {
51
55
  self.isSetupDone = true
@@ -186,10 +190,94 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
186
190
  }
187
191
 
188
192
  if iconType == "sf-symbol" {
189
- buttonNearDoneIcon = UIImage(systemName: icon)
193
+ buttonNearDoneIcon = UIImage(systemName: icon)?.withRenderingMode(.alwaysTemplate)
194
+ print("[DEBUG] Set buttonNearDone SF Symbol icon: \(icon)")
190
195
  } else {
191
- // UIImage(resource: ImageResource(name: "public/monkey.svg", bundle: Bundle.main))
192
- buttonNearDoneIcon = UIImage(named: icon, in: Bundle.main, with: nil)
196
+ // Look in app's web assets/public directory
197
+ guard let webDir = Bundle.main.resourceURL?.appendingPathComponent("public") else {
198
+ print("[DEBUG] Failed to locate web assets directory")
199
+ return
200
+ }
201
+
202
+ // Try several path combinations to find the asset
203
+ let paths = [
204
+ icon, // Just the icon name
205
+ "public/\(icon)", // With public/ prefix
206
+ icon.replacingOccurrences(of: "public/", with: "") // Without public/ prefix
207
+ ]
208
+
209
+ var foundImage = false
210
+
211
+ for path in paths {
212
+ // Try as a direct path from web assets dir
213
+ let assetPath = path.replacingOccurrences(of: "public/", with: "")
214
+ let fileURL = webDir.appendingPathComponent(assetPath)
215
+
216
+ print("[DEBUG] Trying to load from: \(fileURL.path)")
217
+
218
+ if FileManager.default.fileExists(atPath: fileURL.path),
219
+ let data = try? Data(contentsOf: fileURL),
220
+ let img = UIImage(data: data) {
221
+ buttonNearDoneIcon = img.withRenderingMode(.alwaysTemplate)
222
+ print("[DEBUG] Successfully loaded buttonNearDone from web assets: \(fileURL.path)")
223
+ foundImage = true
224
+ break
225
+ }
226
+
227
+ // Try with www directory as an alternative
228
+ if let wwwDir = Bundle.main.resourceURL?.appendingPathComponent("www") {
229
+ let wwwFileURL = wwwDir.appendingPathComponent(assetPath)
230
+
231
+ print("[DEBUG] Trying to load from www dir: \(wwwFileURL.path)")
232
+
233
+ if FileManager.default.fileExists(atPath: wwwFileURL.path),
234
+ let data = try? Data(contentsOf: wwwFileURL),
235
+ let img = UIImage(data: data) {
236
+ buttonNearDoneIcon = img.withRenderingMode(.alwaysTemplate)
237
+ print("[DEBUG] Successfully loaded buttonNearDone from www dir: \(wwwFileURL.path)")
238
+ foundImage = true
239
+ break
240
+ }
241
+ }
242
+
243
+ // Try looking in app bundle assets
244
+ if let iconImage = UIImage(named: path) {
245
+ buttonNearDoneIcon = iconImage.withRenderingMode(.alwaysTemplate)
246
+ print("[DEBUG] Successfully loaded buttonNearDone from app bundle: \(path)")
247
+ foundImage = true
248
+ break
249
+ }
250
+ }
251
+
252
+ if !foundImage {
253
+ print("[DEBUG] Failed to load buttonNearDone icon: \(icon)")
254
+
255
+ // Debug info
256
+ if let resourceURL = Bundle.main.resourceURL {
257
+ print("[DEBUG] Resource URL: \(resourceURL.path)")
258
+
259
+ // List directories to help debugging
260
+ do {
261
+ let contents = try FileManager.default.contentsOfDirectory(atPath: resourceURL.path)
262
+ print("[DEBUG] Root bundle contents: \(contents)")
263
+
264
+ // Check if public or www directories exist
265
+ if contents.contains("public") {
266
+ let publicContents = try FileManager.default.contentsOfDirectory(
267
+ atPath: resourceURL.appendingPathComponent("public").path)
268
+ print("[DEBUG] Public dir contents: \(publicContents)")
269
+ }
270
+
271
+ if contents.contains("www") {
272
+ let wwwContents = try FileManager.default.contentsOfDirectory(
273
+ atPath: resourceURL.appendingPathComponent("www").path)
274
+ print("[DEBUG] WWW dir contents: \(wwwContents)")
275
+ }
276
+ } catch {
277
+ print("[DEBUG] Error listing directories: \(error)")
278
+ }
279
+ }
280
+ }
193
281
  }
194
282
  }
195
283
 
@@ -203,12 +291,63 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
203
291
  let preventDeeplink = call.getBool("preventDeeplink", false)
204
292
  let isAnimated = call.getBool("isAnimated", true)
205
293
 
206
- var disclaimerContent = call.getObject("shareDisclaimer")
294
+ // Validate preShowScript requires isPresentAfterPageLoad
295
+ if call.getString("preShowScript") != nil && !call.getBool("isPresentAfterPageLoad", false) {
296
+ call.reject("preShowScript requires isPresentAfterPageLoad to be true")
297
+ return
298
+ }
299
+
300
+ // Validate closeModal options
301
+ if closeModal {
302
+ if call.getString("closeModalTitle") != nil ||
303
+ call.getString("closeModalDescription") != nil ||
304
+ call.getString("closeModalOk") != nil ||
305
+ call.getString("closeModalCancel") != nil {
306
+ // Store the values to be set after proper initialization
307
+ self.closeModalTitle = closeModalTitle
308
+ self.closeModalDescription = closeModalDescription
309
+ self.closeModalOk = closeModalOk
310
+ self.closeModalCancel = closeModalCancel
311
+ }
312
+ } else {
313
+ // Reject if closeModal is false but closeModal options are provided
314
+ if call.getString("closeModalTitle") != nil ||
315
+ call.getString("closeModalDescription") != nil ||
316
+ call.getString("closeModalOk") != nil ||
317
+ call.getString("closeModalCancel") != nil {
318
+ call.reject("closeModal options require closeModal to be true")
319
+ return
320
+ }
321
+ }
322
+
323
+ // Validate shareDisclaimer requires shareSubject
324
+ if call.getString("shareSubject") == nil && call.getObject("shareDisclaimer") != nil {
325
+ call.reject("shareDisclaimer requires shareSubject to be provided")
326
+ return
327
+ }
328
+
329
+ // Validate buttonNearDone compatibility with toolbar type
330
+ if call.getString("buttonNearDone") != nil {
331
+ let toolbarType = call.getString("toolbarType", "")
332
+ if toolbarType == "activity" || toolbarType == "navigation" || toolbarType == "blank" {
333
+ call.reject("buttonNearDone is not compatible with toolbarType: " + toolbarType)
334
+ return
335
+ }
336
+ }
337
+
338
+ var disclaimerContent: JSObject?
339
+ if let shareDisclaimerRaw = call.getObject("shareDisclaimer"), !shareDisclaimerRaw.isEmpty {
340
+ disclaimerContent = shareDisclaimerRaw
341
+ }
342
+
207
343
  let toolbarType = call.getString("toolbarType", "")
208
344
  let backgroundColor = call.getString("backgroundColor", "black") == "white" ? UIColor.white : UIColor.black
209
- if toolbarType != "activity" {
210
- disclaimerContent = nil
211
- }
345
+
346
+ // Don't null out shareDisclaimer regardless of toolbarType
347
+ // if toolbarType != "activity" {
348
+ // disclaimerContent = nil
349
+ // }
350
+
212
351
  let ignoreUntrustedSSLError = call.getBool("ignoreUntrustedSSLError", false)
213
352
 
214
353
  self.isPresentAfterPageLoad = call.getBool("isPresentAfterPageLoad", false)
@@ -230,46 +369,214 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
230
369
  }
231
370
 
232
371
  webViewController.source = .remote(url)
233
- webViewController.leftNavigationBarItemTypes = self.getToolbarItems(toolbarType: toolbarType) + [.reload]
372
+ webViewController.leftNavigationBarItemTypes = []
234
373
  webViewController.toolbarItemTypes = []
235
- webViewController.doneBarButtonItemPosition = .right
236
374
 
237
- webViewController.buttonNearDoneIcon = buttonNearDoneIcon
375
+ // Configure close button based on showArrow
376
+ let showArrow = call.getBool("showArrow", false)
377
+ if showArrow {
378
+ // When showArrow is true, put arrow on left
379
+ webViewController.doneBarButtonItemPosition = .left
380
+ webViewController.showArrowAsClose = true
381
+ } else {
382
+ // Default X on right
383
+ webViewController.doneBarButtonItemPosition = toolbarType == "activity" ? .none : .right
384
+ webViewController.showArrowAsClose = false
385
+ }
386
+
387
+ // Configure navigation buttons based on toolbarType
388
+ if toolbarType == "activity" {
389
+ // Activity mode should ONLY have:
390
+ // 1. Close button (if not hidden by doneBarButtonItemPosition)
391
+ // 2. Share button (if shareSubject is provided)
392
+ webViewController.leftNavigationBarItemTypes = [] // Clear any left items
393
+ webViewController.rightNavigaionBarItemTypes = [] // Clear any right items
394
+
395
+ // Only add share button if subject is provided
396
+ if call.getString("shareSubject") != nil {
397
+ // Add share button to right bar
398
+ webViewController.rightNavigaionBarItemTypes.append(.activity)
399
+ print("[DEBUG] Activity mode: Added share button, shareSubject: \(call.getString("shareSubject") ?? "nil")")
400
+ } else {
401
+ // In activity mode, always make the share button visible by setting a default shareSubject
402
+ webViewController.shareSubject = "Share"
403
+ webViewController.rightNavigaionBarItemTypes.append(.activity)
404
+ print("[DEBUG] Activity mode: Setting default shareSubject")
405
+ }
238
406
 
239
- if call.getBool("showArrow", false) {
240
- webViewController.stopBarButtonItemImage = UIImage(named: "Forward@3x", in: Bundle(for: InAppBrowserPlugin.self), compatibleWith: nil)
407
+ // Set done button position based on showArrow
408
+ if showArrow {
409
+ webViewController.doneBarButtonItemPosition = .left
410
+ } else {
411
+ // In activity mode, keep the done button visible even when showArrow is false
412
+ webViewController.doneBarButtonItemPosition = .right
413
+ }
414
+ } else if toolbarType == "navigation" {
415
+ // Navigation mode puts back/forward on the left
416
+ webViewController.leftNavigationBarItemTypes = [.back, .forward]
417
+ if showReloadButton {
418
+ webViewController.leftNavigationBarItemTypes.append(.reload)
419
+ }
420
+
421
+ // Only add share button if subject is provided
422
+ if call.getString("shareSubject") != nil {
423
+ // Add share button to right navigation bar
424
+ webViewController.rightNavigaionBarItemTypes.append(.activity)
425
+ }
426
+ } else {
427
+ // Other modes may have reload button
428
+ if showReloadButton {
429
+ webViewController.leftNavigationBarItemTypes.append(.reload)
430
+ }
431
+
432
+ // Only add share button if subject is provided
433
+ if call.getString("shareSubject") != nil {
434
+ // Add share button to right navigation bar
435
+ webViewController.rightNavigaionBarItemTypes.append(.activity)
436
+ }
437
+ }
438
+
439
+ // Set buttonNearDoneIcon if provided
440
+ if let buttonNearDoneIcon = buttonNearDoneIcon {
441
+ webViewController.buttonNearDoneIcon = buttonNearDoneIcon
442
+ print("[DEBUG] Button near done icon set: \(buttonNearDoneIcon)")
241
443
  }
242
444
 
243
445
  webViewController.capBrowserPlugin = self
244
446
  webViewController.title = call.getString("title", "New Window")
245
- webViewController.shareSubject = call.getString("shareSubject")
447
+ // Only set shareSubject if not already set for activity mode
448
+ if webViewController.shareSubject == nil {
449
+ webViewController.shareSubject = call.getString("shareSubject")
450
+ }
246
451
  webViewController.shareDisclaimer = disclaimerContent
452
+
453
+ // Debug shareDisclaimer
454
+ if let disclaimer = disclaimerContent {
455
+ print("[DEBUG] Share disclaimer set: \(disclaimer)")
456
+ } else {
457
+ print("[DEBUG] No share disclaimer set")
458
+ }
459
+
247
460
  webViewController.preShowScript = call.getString("preShowScript")
248
461
  webViewController.websiteTitleInNavigationBar = call.getBool("visibleTitle", true)
462
+ webViewController.ignoreUntrustedSSLError = ignoreUntrustedSSLError
463
+
464
+ // Set text zoom if specified
465
+ if let textZoom = call.getInt("textZoom") {
466
+ webViewController.textZoom = textZoom
467
+ }
468
+
469
+ // Set closeModal properties after proper initialization
249
470
  if closeModal {
250
471
  webViewController.closeModal = true
251
- webViewController.closeModalTitle = closeModalTitle
252
- webViewController.closeModalDescription = closeModalDescription
253
- webViewController.closeModalOk = closeModalOk
254
- webViewController.closeModalCancel = closeModalCancel
472
+ webViewController.closeModalTitle = self.closeModalTitle ?? closeModalTitle
473
+ webViewController.closeModalDescription = self.closeModalDescription ?? closeModalDescription
474
+ webViewController.closeModalOk = self.closeModalOk ?? closeModalOk
475
+ webViewController.closeModalCancel = self.closeModalCancel ?? closeModalCancel
255
476
  }
256
- webViewController.ignoreUntrustedSSLError = ignoreUntrustedSSLError
257
477
 
258
478
  self.navigationWebViewController = UINavigationController.init(rootViewController: webViewController)
259
479
  self.navigationWebViewController?.navigationBar.isTranslucent = false
260
480
  self.navigationWebViewController?.toolbar.isTranslucent = false
261
- self.navigationWebViewController?.navigationBar.backgroundColor = backgroundColor
262
- self.navigationWebViewController?.toolbar.backgroundColor = backgroundColor
263
- self.navigationWebViewController?.toolbar.tintColor = backgroundColor == UIColor.black ? UIColor.white : UIColor.black
481
+
482
+ // Ensure no lines or borders appear by default
483
+ self.navigationWebViewController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
484
+ self.navigationWebViewController?.navigationBar.shadowImage = UIImage()
485
+ self.navigationWebViewController?.navigationBar.setValue(true, forKey: "hidesShadow")
486
+ self.navigationWebViewController?.toolbar.setShadowImage(UIImage(), forToolbarPosition: .any)
487
+
488
+ // Handle toolbar color
489
+ if let toolbarColor = call.getString("toolbarColor"), self.isHexColorCode(toolbarColor) {
490
+ // If specific color provided, use it
491
+ let color = UIColor(hexString: toolbarColor)
492
+
493
+ // Apply to status bar and navigation bar area with a single colored view
494
+ webViewController.setupStatusBarBackground(color: color)
495
+
496
+ // Set status bar style based on toolbar color
497
+ let isDark = self.isDarkColor(color)
498
+ webViewController.statusBarStyle = isDark ? .lightContent : .darkContent
499
+ webViewController.updateStatusBarStyle()
500
+
501
+ // Apply text color
502
+ let textColor: UIColor
503
+ if let toolbarTextColor = call.getString("toolbarTextColor"), self.isHexColorCode(toolbarTextColor) {
504
+ textColor = UIColor(hexString: toolbarTextColor)
505
+ } else {
506
+ textColor = isDark ? UIColor.white : UIColor.black
507
+ }
508
+
509
+ // Apply tint color to all UI elements without changing background
510
+ self.navigationWebViewController?.navigationBar.tintColor = textColor
511
+ webViewController.tintColor = textColor
512
+ self.navigationWebViewController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: textColor]
513
+ } else {
514
+ // Use system appearance
515
+ let isDarkMode = UITraitCollection.current.userInterfaceStyle == .dark
516
+ let backgroundColor = isDarkMode ? UIColor.black : UIColor.white
517
+ let textColor: UIColor
518
+
519
+ if let toolbarTextColor = call.getString("toolbarTextColor"), self.isHexColorCode(toolbarTextColor) {
520
+ textColor = UIColor(hexString: toolbarTextColor)
521
+ } else {
522
+ textColor = isDarkMode ? UIColor.white : UIColor.black
523
+ }
524
+
525
+ // Apply colors
526
+ webViewController.setupStatusBarBackground(color: backgroundColor)
527
+ webViewController.tintColor = textColor
528
+ self.navigationWebViewController?.navigationBar.tintColor = textColor
529
+ self.navigationWebViewController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: textColor]
530
+ webViewController.statusBarStyle = isDarkMode ? .lightContent : .darkContent
531
+ webViewController.updateStatusBarStyle()
532
+
533
+ }
534
+
264
535
  self.navigationWebViewController?.modalPresentationStyle = .fullScreen
265
536
  if toolbarType == "blank" {
266
537
  self.navigationWebViewController?.navigationBar.isHidden = true
267
538
  webViewController.blankNavigationTab = true
539
+
540
+ // Even with hidden navigation bar, we need to set proper status bar appearance
541
+ // If toolbarColor is explicitly set, use that for status bar style
542
+ if let toolbarColor = call.getString("toolbarColor"), self.isHexColorCode(toolbarColor) {
543
+ let color = UIColor(hexString: toolbarColor)
544
+ let isDark = self.isDarkColor(color)
545
+ webViewController.statusBarStyle = isDark ? .lightContent : .darkContent
546
+ webViewController.updateStatusBarStyle()
547
+
548
+ // Apply status bar background color via the special view
549
+ webViewController.setupStatusBarBackground(color: color)
550
+
551
+ // Apply background color to whole view to ensure no gaps
552
+ webViewController.view.backgroundColor = color
553
+ self.navigationWebViewController?.view.backgroundColor = color
554
+
555
+ // Apply status bar background color
556
+ if let navController = self.navigationWebViewController {
557
+ navController.view.backgroundColor = color
558
+ }
559
+ } else {
560
+ // Follow system appearance if no specific color
561
+ let isDarkMode = UITraitCollection.current.userInterfaceStyle == .dark
562
+ let backgroundColor = isDarkMode ? UIColor.black : UIColor.white
563
+ webViewController.statusBarStyle = isDarkMode ? .lightContent : .darkContent
564
+ webViewController.updateStatusBarStyle()
565
+
566
+ // Apply status bar background color via the special view
567
+ webViewController.setupStatusBarBackground(color: backgroundColor)
568
+
569
+ // Set appropriate background color
570
+ if let navController = self.navigationWebViewController {
571
+ navController.view.backgroundColor = backgroundColor
572
+ }
573
+ }
574
+
268
575
  }
269
- if showReloadButton {
270
- let toolbarItems = self.getToolbarItems(toolbarType: toolbarType)
271
- webViewController.leftNavigationBarItemTypes = toolbarItems + [.reload]
272
- }
576
+
577
+ // We don't use the toolbar anymore, always hide it
578
+ self.navigationWebViewController?.setToolbarHidden(true, animated: false)
579
+
273
580
  if !self.isPresentAfterPageLoad {
274
581
  self.presentView(isAnimated: isAnimated)
275
582
  }
@@ -277,17 +584,6 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
277
584
  }
278
585
  }
279
586
 
280
- func getToolbarItems(toolbarType: String) -> [BarButtonItemType] {
281
- var result: [BarButtonItemType] = []
282
- if toolbarType == "activity" {
283
- result.append(.activity)
284
- } else if toolbarType == "navigation" {
285
- result.append(.back)
286
- result.append(.forward)
287
- }
288
- return result
289
- }
290
-
291
587
  @objc func reload(_ call: CAPPluginCall) {
292
588
  self.webViewController?.reload()
293
589
  call.resolve()
@@ -397,14 +693,9 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
397
693
  self.navigationWebViewController?.navigationBar.isTranslucent = false
398
694
  self.navigationWebViewController?.toolbar.isTranslucent = false
399
695
  self.navigationWebViewController?.navigationBar.backgroundColor = .white
400
- let inputString: String = call.getString("toolbarColor", "#ffffff")
401
- var color: UIColor = UIColor(hexString: "#ffffff")
402
- if self.isHexColorCode(inputString) {
403
- color = UIColor(hexString: inputString)
404
- } else {
405
- print("\(inputString) is not a valid hex color code.")
406
- }
407
- self.navigationWebViewController?.toolbar.backgroundColor = color
696
+ self.navigationWebViewController?.toolbar.backgroundColor = .white
697
+ self.navigationWebViewController?.toolbar.tintColor = .black
698
+
408
699
  self.navigationWebViewController?.modalPresentationStyle = .fullScreen
409
700
  if !self.isPresentAfterPageLoad {
410
701
  self.presentView()
@@ -459,4 +750,13 @@ public class InAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
459
750
  }
460
751
  return credentials
461
752
  }
753
+
754
+ private func isDarkColor(_ color: UIColor) -> Bool {
755
+ let components = color.cgColor.components ?? []
756
+ let red = components[0]
757
+ let green = components[1]
758
+ let blue = components[2]
759
+ let brightness = (red * 299 + green * 587 + blue * 114) / 1000
760
+ return brightness < 0.5
761
+ }
462
762
  }