Skip to content

Commit

Permalink
feat(ios): ios injectJavaScriptObject (#3157)
Browse files Browse the repository at this point in the history
* feat(ios): injectedJavaScriptObject props connect

* feat(ios): injectedJavaScriptObject ios component props

* feat(ios): injectedObjectJsonScript addUserScript

* refactor(ios): type position lines

* revert: src/WebViewTypes.ts

* docs: support injectedJavaScriptObject ios

* remove log

* fix(ios): return string single quote
  • Loading branch information
gronxb committed Feb 13, 2024
1 parent 8f21868 commit 8013944
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 9 deletions.
1 change: 1 addition & 0 deletions apple/RNCWebView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
REMAP_WEBVIEW_STRING_PROP(injectedJavaScriptBeforeContentLoaded)
REMAP_WEBVIEW_PROP(injectedJavaScriptForMainFrameOnly)
REMAP_WEBVIEW_PROP(injectedJavaScriptBeforeContentLoadedForMainFrameOnly)
REMAP_WEBVIEW_STRING_PROP(injectedJavaScriptObject)
REMAP_WEBVIEW_PROP(javaScriptEnabled)
REMAP_WEBVIEW_PROP(javaScriptCanOpenWindowsAutomatically)
REMAP_WEBVIEW_PROP(allowFileAccessFromFileURLs)
Expand Down
1 change: 1 addition & 0 deletions apple/RNCWebViewImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
@property (nonatomic, copy) NSString * _Nullable injectedJavaScriptBeforeContentLoaded;
@property (nonatomic, assign) BOOL injectedJavaScriptForMainFrameOnly;
@property (nonatomic, assign) BOOL injectedJavaScriptBeforeContentLoadedForMainFrameOnly;
@property (nonatomic, copy) NSString * _Nullable injectedJavaScriptObject;
@property (nonatomic, assign) BOOL scrollEnabled;
@property (nonatomic, assign) BOOL sharedCookiesEnabled;
@property (nonatomic, assign) BOOL autoManageStatusBarEnabled;
Expand Down
33 changes: 28 additions & 5 deletions apple/RNCWebViewImpl.m
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ @interface RNCWebViewImpl () <WKUIDelegate, WKNavigationDelegate, WKScriptMessag

@property (nonatomic, copy) RNCWKWebView *webView;
@property (nonatomic, strong) WKUserScript *postMessageScript;
@property (nonatomic, strong) WKUserScript *injectedObjectJsonScript;
@property (nonatomic, strong) WKUserScript *atStartScript;
@property (nonatomic, strong) WKUserScript *atEndScript;
@end
Expand Down Expand Up @@ -1627,6 +1628,26 @@ - (void)setInjectedJavaScript:(NSString *)source {
}
}

- (void)setInjectedJavaScriptObject:(NSString *)source
{
self.injectedObjectJsonScript = [
[WKUserScript alloc]
initWithSource: [
NSString
stringWithFormat:
@"window.%@ ??= {};"
"window.%@.injectedObjectJson = function () {"
" return `%@`;"
"};", MessageHandlerName, MessageHandlerName, source
]
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
/* TODO: For a separate (minor) PR: use logic like this (as react-native-wkwebview does) so that messaging can be used in all frames if desired.
* I am keeping it as YES for consistency with previous behaviour. */
// forMainFrameOnly:_messagingEnabledForMainFrameOnly
forMainFrameOnly:YES
];
}

- (void)setEnableApplePay:(BOOL)enableApplePay {
_enableApplePay = enableApplePay;
if(_webView != nil){
Expand Down Expand Up @@ -1665,11 +1686,10 @@ - (void)setMessagingEnabled:(BOOL)messagingEnabled {
initWithSource: [
NSString
stringWithFormat:
@"window.%@ = {"
" postMessage: function (data) {"
" window.webkit.messageHandlers.%@.postMessage(String(data));"
" }"
"};", MessageHandlerName, MessageHandlerName
@"window.%@ ??= {};"
"window.%@.postMessage = function (data) {"
" window.webkit.messageHandlers.%@.postMessage(String(data));"
"};", MessageHandlerName, MessageHandlerName, MessageHandlerName
]
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
/* TODO: For a separate (minor) PR: use logic like this (as react-native-wkwebview does) so that messaging can be used in all frames if desired.
Expand Down Expand Up @@ -1827,6 +1847,9 @@ - (void)resetupScripts:(WKWebViewConfiguration *)wkWebViewConfig {
if (self.atStartScript) {
[wkWebViewConfig.userContentController addUserScript:self.atStartScript];
}
if (self.injectedObjectJsonScript) {
[wkWebViewConfig.userContentController addUserScript:self.injectedObjectJsonScript];
}
}

- (NSURLRequest *)requestForSource:(id)json {
Expand Down
1 change: 1 addition & 0 deletions apple/RNCWebViewManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ - (RNCView *)view
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptBeforeContentLoaded, NSString)
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptForMainFrameOnly, BOOL)
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptBeforeContentLoadedForMainFrameOnly, BOOL)
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScriptObject, NSString)
RCT_EXPORT_VIEW_PROPERTY(javaScriptEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(javaScriptCanOpenWindowsAutomatically, BOOL)
RCT_EXPORT_VIEW_PROPERTY(allowFileAccessFromFileURLs, BOOL)
Expand Down
2 changes: 1 addition & 1 deletion docs/Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ By setting `injectedJavaScriptBeforeContentLoadedForMainFrameOnly: false`, the J
> Note on Android Compatibility: For applications targeting `Build.VERSION_CODES.N` or later, JavaScript state from an empty WebView is no longer persisted across navigations like `loadUrl(java.lang.String)`. For example, global variables and functions defined before calling `loadUrl(java.lang.String)` will not exist in the loaded page. Applications should use the Android Native API `addJavascriptInterface(Object, String)` instead to persist JavaScript objects across navigations.

#### The `injectedJavaScriptObject` prop (Android Only)
#### The `injectedJavaScriptObject` prop

Due to the Android race condition mentioned above, this more reliable prop was added. While you cannot execute arbitrary JavaScript, you can make an arbitrary JS object available to the JS run in the webview prior to the page load completing.

Expand Down
2 changes: 1 addition & 1 deletion docs/Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ Inject any JavaScript object into the webview so it is available to the JS runni

| Type | Required | Platform |
| ---- | -------- | ------------------------------------------------- |
| obj | No | Android only |
| obj | No | iOS, Android |

Example:

Expand Down
1 change: 0 additions & 1 deletion example/examples/Injection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ export default class Injection extends Component<Props, State> {
// Example usage of injectedJavaScriptObject({hello: 'world'}), see above
const injectedObjectJson = window.ReactNativeWebView.injectedObjectJson();
// injectedJavaScriptObject is only available on Android
if (injectedObjectJson) {
const injectedObject = JSON.parse(injectedObjectJson);
console.log("injectedJavaScriptObject: ", injectedObject); // injectedJavaScriptObject: { hello: 'world' }
Expand Down
2 changes: 1 addition & 1 deletion src/RNCWebViewNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export interface NativeProps extends ViewProps {
thirdPartyCookiesEnabled?: boolean;
// Workaround to watch if listener if defined
hasOnScroll?: boolean;
injectedJavaScriptObject?: string;
// !Android only

// iOS only
Expand Down Expand Up @@ -254,6 +253,7 @@ export interface NativeProps extends ViewProps {
baseUrl?: string;
}>;
userAgent?: string;
injectedJavaScriptObject?: string;
}

export interface NativeCommands {
Expand Down
2 changes: 2 additions & 0 deletions src/WebView.ios.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps>(({
injectedJavaScriptBeforeContentLoaded,
injectedJavaScriptForMainFrameOnly = true,
injectedJavaScriptBeforeContentLoadedForMainFrameOnly = true,
injectedJavaScriptObject,
startInLoadingState,
onNavigationStateChange,
onLoadStart,
Expand Down Expand Up @@ -201,6 +202,7 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps>(({
injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded}
injectedJavaScriptForMainFrameOnly={injectedJavaScriptForMainFrameOnly}
injectedJavaScriptBeforeContentLoadedForMainFrameOnly={injectedJavaScriptBeforeContentLoadedForMainFrameOnly}
injectedJavaScriptObject={JSON.stringify(injectedJavaScriptObject)}
dataDetectorTypes={!dataDetectorTypes || Array.isArray(dataDetectorTypes) ? dataDetectorTypes : [dataDetectorTypes]}
allowsAirPlayForMediaPlayback={allowsAirPlayForMediaPlayback}
allowsInlineMediaPlayback={allowsInlineMediaPlayback}
Expand Down

0 comments on commit 8013944

Please sign in to comment.