Browse Source

feat(iOS): Add Hardware Silence (#1218)

* Fixes Issue #1140

Fixes https://github.com/react-native-community/react-native-webview/issues/1140
Based on a solution found at: https://stackoverflow.com/questions/56460362/how-to-force-wkwebview-to-ignore-hardware-silent-switch-on-ios
I changed the code found in the linked source from Swift to Objective-C, as required by this project. WARNING: I haven't used Swift before and very limited experience with Objective-C.

- For me this seems to work, but it is not the cleanest solution in my opinion.
- It might also be possible to play generated sound (i.e. using oscillator) instead of hardcoding the silent base64 mp3 data.
- Maybe ignoring silence switch should only be done if a parameter is supplied

* fixes import path

* adds documentation for ignoreSilentHardwareSwitch

* adds ignoreSilentHardwareSwitch parameter

* reverting back to old import path

* Update Guide.md

Co-authored-by: Dominik Beste <dominik.beste@gmail.com>
RedPandaTronics 4 years ago
parent
commit
d4ab332891
No account linked to committer's email address
3 changed files with 63 additions and 0 deletions
  1. 7
    0
      docs/Guide.md
  2. 11
    0
      docs/Reference.md
  3. 45
    0
      ios/RNCWebView.m

+ 7
- 0
docs/Guide.md View File

@@ -517,3 +517,10 @@ const App = () => {
517 517
 ```
518 518
 
519 519
 Note that these cookies will only be sent on the first request unless you use the technique above for [setting custom headers on each page load](#Setting-Custom-Headers).
520
+
521
+### Hardware Silence Switch
522
+There are some inconsistencies in how the hardware silence switch is handled between embedded `audio` and `video` elements and between iOS and Android platforms.
523
+
524
+Audio on `iOS` will be muted when the hardware silence switch is in the on position, unless the `ignoreSilentHardwareSwitch` parameter is set to true.
525
+
526
+Video on `iOS` will always ignore the hardware silence switch.

+ 11
- 0
docs/Reference.md View File

@@ -64,6 +64,7 @@ This document lays out the current public properties and methods for the React N
64 64
 - [`allowsLinkPreview`](Reference.md#allowsLinkPreview)
65 65
 - [`sharedCookiesEnabled`](Reference.md#sharedCookiesEnabled)
66 66
 - [`textZoom`](Reference.md#textZoom)
67
+- [`ignoreSilentHardwareSwitch`](Reference.md#ignoreSilentHardwareSwitch)
67 68
 
68 69
 ## Methods Index
69 70
 
@@ -1127,6 +1128,16 @@ Example:
1127 1128
 
1128 1129
 `<WebView textZoom={100} />`
1129 1130
 
1131
+### `ignoreSilentHardwareSwitch`
1132
+
1133
+(ios only)
1134
+
1135
+When set to true the hardware silent switch is ignored. Default: `false`
1136
+
1137
+| Type    | Required | Platform |
1138
+| ------- | -------- | -------- |
1139
+| boolean | No       | iOS      |
1140
+
1130 1141
 ## Methods
1131 1142
 
1132 1143
 ### `extraNativeComponentConfig()`

+ 45
- 0
ios/RNCWebView.m View File

@@ -140,6 +140,15 @@ static NSDictionary* customCertificatesForHost;
140 140
   }
141 141
 
142 142
 #if !TARGET_OS_OSX
143
+    [[NSNotificationCenter defaultCenter]addObserver:self
144
+    selector:@selector(appDidBecomeActive)
145
+        name:UIApplicationDidBecomeActiveNotification
146
+      object:nil];
147
+    
148
+    [[NSNotificationCenter defaultCenter]addObserver:self
149
+    selector:@selector(appWillResignActive)
150
+        name:UIApplicationWillResignActiveNotification
151
+      object:nil];
143 152
   if (@available(iOS 12.0, *)) {
144 153
     // Workaround for a keyboard dismissal bug present in iOS 12
145 154
     // https://openradar.appspot.com/radar?id=5018321736957952
@@ -163,6 +172,7 @@ static NSDictionary* customCertificatesForHost;
163 172
                                                selector:@selector(hideFullScreenVideoStatusBars)
164 173
                                                    name:UIWindowDidBecomeHiddenNotification
165 174
                                                  object:nil];
175
+      
166 176
   }
167 177
 #endif // !TARGET_OS_OSX
168 178
   return self;
@@ -1031,6 +1041,37 @@ static NSDictionary* customCertificatesForHost;
1031 1041
   }];
1032 1042
 }
1033 1043
 
1044
+-(void)forceIgnoreSilentHardwareSwitch:(BOOL)initialSetup
1045
+{
1046
+    NSString *mp3Str = @"data:audio/mp3;base64,//tAxAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAFAAAESAAzMzMzMzMzMzMzMzMzMzMzMzMzZmZmZmZmZmZmZmZmZmZmZmZmZmaZmZmZmZmZmZmZmZmZmZmZmZmZmczMzMzMzMzMzMzMzMzMzMzMzMzM//////////////////////////8AAAA5TEFNRTMuMTAwAZYAAAAAAAAAABQ4JAMGQgAAOAAABEhNIZS0AAAAAAD/+0DEAAPH3Yz0AAR8CPqyIEABp6AxjG/4x/XiInE4lfQDFwIIRE+uBgZoW4RL0OLMDFn6E5v+/u5ehf76bu7/6bu5+gAiIQGAABQIUJ0QolFghEn/9PhZQpcUTpXMjo0OGzRCZXyKxoIQzB2KhCtGobpT9TRVj/3Pmfp+f8X7Pu1B04sTnc3s0XhOlXoGVCMNo9X//9/r6a10TZEY5DsxqvO7mO5qFvpFCmKIjhpSItGsUYcRO//7QsQRgEiljQIAgLFJAbIhNBCa+JmorCbOi5q9nVd2dKnusTMQg4MFUlD6DQ4OFijwGAijRMfLbHG4nLVTjydyPlJTj8pfPflf9/5GD950A5e+jsrmNZSjSirjs1R7hnkia8vr//l/7Nb+crvr9Ok5ZJOylUKRxf/P9Zn0j2P4pJYXyKkeuy5wUYtdmOu6uobEtFqhIJViLEKIjGxchGev/L3Y0O3bwrIOszTBAZ7Ih28EUaSOZf/7QsQfg8fpjQIADN0JHbGgQBAZ8T//y//t/7d/2+f5m7MdCeo/9tdkMtGLbt1tqnabRroO1Qfvh20yEbei8nfDXP7btW7f9/uO9tbe5IvHQbLlxpf3DkAk0ojYcv///5/u3/7PTfGjPEPUvt5D6f+/3Lea4lz4tc4TnM/mFPrmalWbboeNiNyeyr+vufttZuvrVrt/WYv3T74JFo8qEDiJqJrmDTs///v99xDku2xG02jjunrICP/7QsQtA8kpkQAAgNMA/7FgQAGnobgfghgqA+uXwWQ3XFmGimSbe2X3ksY//KzK1a2k6cnNWOPJnPWUsYbKqkh8RJzrVf///P///////4vyhLKHLrCb5nIrYIUss4cthigL1lQ1wwNAc6C1pf1TIKRSkt+a//z+yLVcwlXKSqeSuCVQFLng2h4AFAFgTkH+Z/8jTX/zr//zsJV/5f//5UX/0ZNCNCCaf5lTCTRkaEdhNP//n/KUjf/7QsQ5AEhdiwAAjN7I6jGddBCO+WGTQ1mXrYatSAgaykxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==";
1047
+    NSString *scr;
1048
+    if (initialSetup) {
1049
+        scr = [NSString stringWithFormat:@"var s=new Audio('%@');s.id='wkwebviewAudio';s.controls=false;s.loop=true;s.play();document.body.appendChild(s);true", mp3Str];
1050
+    } else {
1051
+        scr = [NSString stringWithFormat:@"var s=document.getElementById('wkwebviewAudio');s.src=null;s.parentNode.removeChild(s);s=null;s=new Audio('%@');s.id='wkwebviewAudio';s.controls=false;s.loop=true;s.play();document.body.appendChild(s);true", mp3Str];
1052
+    }
1053
+    [self evaluateJS: scr thenCall: nil];
1054
+}
1055
+
1056
+-(void)disableIgnoreSilentSwitch
1057
+{
1058
+    [self evaluateJS: @"document.getElementById('wkwebviewAudio').src=null;true" thenCall: nil];
1059
+}
1060
+
1061
+-(void)appDidBecomeActive
1062
+{
1063
+    if (_ignoreSilentHardwareSwitch) {
1064
+      [self forceIgnoreSilentHardwareSwitch:false];
1065
+    }
1066
+}
1067
+
1068
+-(void)appWillResignActive
1069
+{
1070
+  if (_ignoreSilentHardwareSwitch) {
1071
+    [self disableIgnoreSilentSwitch];
1072
+  }
1073
+}
1074
+
1034 1075
 /**
1035 1076
  * Called when the navigation is complete.
1036 1077
  * @see https://fburl.com/rtys6jlb
@@ -1038,6 +1079,10 @@ static NSDictionary* customCertificatesForHost;
1038 1079
 - (void)webView:(WKWebView *)webView
1039 1080
   didFinishNavigation:(WKNavigation *)navigation
1040 1081
 {
1082
+  if (_ignoreSilentHardwareSwitch) {
1083
+    [self forceIgnoreSilentHardwareSwitch:true];
1084
+  }
1085
+    
1041 1086
   if (_onLoadingFinish) {
1042 1087
     _onLoadingFinish([self baseEvent]);
1043 1088
   }