Skip to content

Commit

Permalink
Merge pull request #231 from klarna/klarna_standalone_webview_compone…
Browse files Browse the repository at this point in the history
…nt_api_changes

Change some prop signatures to match the official React Native WebView
  • Loading branch information
NMGuner authored Dec 22, 2023
2 parents adb8691 + aefac65 commit 0e52a4b
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 216 deletions.
8 changes: 4 additions & 4 deletions TestApp/src/standalonewebview/StandaloneWebViewScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, {useRef, useState} from 'react';
import {
KlarnaStandaloneWebView,
KlarnaWebViewKlarnaMessageEvent,
KlarnaWebViewNavigationError,
KlarnaWebViewError,
KlarnaWebViewNavigationEvent,
KlarnaWebViewProgressEvent,
KlarnaWebViewRenderProcessGoneEvent,
Expand Down Expand Up @@ -122,10 +122,10 @@ export default function StandaloneWebViewScreen() {
onLoadStart={(event: KlarnaWebViewNavigationEvent) => {
onEvent('onLoadStart', JSON.stringify(event));
}}
onLoad={(event: KlarnaWebViewNavigationEvent) => {
onEvent('onLoad', JSON.stringify(event));
onLoadEnd={(event: KlarnaWebViewNavigationEvent) => {
onEvent('onLoadEnd', JSON.stringify(event));
}}
onError={(event: KlarnaWebViewNavigationError) => {
onError={(event: KlarnaWebViewError) => {
onEvent('onError', JSON.stringify(event));
}}
onLoadProgress={(event: KlarnaWebViewProgressEvent) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public enum Event {
// This event is sent just before loading a URL
ON_LOAD_START("onLoadStart"),
// This event is sent when loading a URL is done
ON_LOAD("onLoad"),
ON_LOAD_END("onLoadEnd"),
// This event is sent when loading a URL encounters an error
ON_ERROR("onError"),
// This event is sent when the progress of loading a page changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
Expand All @@ -17,8 +16,6 @@
import java.util.HashMap;
import java.util.Map;

// TODO: Double-check that we're sending the correct values for parameters of the events.

/**
* This class is responsible for sending some KlarnaStandaloneWebView-related events to the React Native side.
*/
Expand All @@ -29,14 +26,14 @@ public class KlarnaStandaloneWebViewEventSender {
private static final String PARAM_NAME_PROGRESS_EVENT = "progressEvent";
private static final String PARAM_NAME_KLARNA_MESSAGE_EVENT = "klarnaMessageEvent";
private static final String PARAM_NAME_RENDER_PROCESS_GONE_EVENT = "renderProcessGoneEvent";
private static final String PARAM_NAME_ERROR_MESSAGE = "errorMessage";
private static final String PARAM_NAME_EVENT = "event";
private static final String PARAM_NAME_NEW_URL = "newUrl";
private static final String PARAM_NAME_CODE = "code";
private static final String PARAM_NAME_DESCRIPTION = "description";
private static final String PARAM_NAME_TITLE = "title";
private static final String PARAM_NAME_URL = "url";
private static final String PARAM_NAME_CAN_GO_BACK = "canGoBack";
private static final String PARAM_NAME_CAN_GO_FORWARD = "canGoForward";
private static final String PARAM_NAME_PROGRESS = "progress";
private static final String PARAM_NAME_IS_LOADING = "isLoading";
private static final String PARAM_NAME_WEB_VIEW_STATE = "webViewState";
private static final String PARAM_NAME_LOADING = "loading";
private static final String PARAM_NAME_ACTION = "action";
private static final String PARAM_NAME_DID_CRASH = "didCrash";

Expand All @@ -47,40 +44,48 @@ public class KlarnaStandaloneWebViewEventSender {
}

public void sendLoadProgressEvent(@Nullable KlarnaStandaloneWebView view, int progress) {
ReadableMap webViewStateMap = (view == null) ? Arguments.createMap() : buildWebViewStateMap(view.getUrl(), view.getTitle(), progress);
WritableMap webViewMap = buildWebViewMap(view, null);
webViewMap.putDouble(PARAM_NAME_PROGRESS, progress);
WritableMap params = ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_PROGRESS_EVENT, webViewStateMap);
put(PARAM_NAME_PROGRESS_EVENT, webViewMap);
}});
postEventForView(KlarnaStandaloneWebViewEvent.Event.ON_LOAD_PROGRESS, params, view);
}

public void sendErrorEvent(@Nullable KlarnaStandaloneWebView view, String description) {
ReadableMap navigationErrorMap = ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_ERROR_MESSAGE, description);
}});
public void sendErrorEvent(@Nullable KlarnaStandaloneWebView view, int code, String description) {
WritableMap webViewMap = buildWebViewMap(view, null);
webViewMap.putDouble(PARAM_NAME_CODE, code);
webViewMap.putString(PARAM_NAME_DESCRIPTION, description);
WritableMap params = ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_NAVIGATION_ERROR, navigationErrorMap);
put(PARAM_NAME_NAVIGATION_ERROR, webViewMap);
}});
postEventForView(KlarnaStandaloneWebViewEvent.Event.ON_ERROR, params, view);
}

public void sendNavigationEvent(@Nullable KlarnaStandaloneWebView view, KlarnaStandaloneWebViewEvent.Event event) {
public void sendNavigationEvent(@Nullable KlarnaStandaloneWebView view, KlarnaStandaloneWebViewEvent.Event event, String url) {
WritableMap webViewMap = buildWebViewMap(view, url);
WritableMap params = ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_NAVIGATION_EVENT, buildNavigationEventMap(view, event));
put(PARAM_NAME_NAVIGATION_EVENT, webViewMap);
}});
postEventForView(event, params, view);
}

public void sendKlarnaMessageEvent(@Nullable KlarnaStandaloneWebView view, @NonNull KlarnaProductEvent klarnaProductEvent) {
ReadableMap eventMap = ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_ACTION, klarnaProductEvent.getAction());
}});
WritableMap params = ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_KLARNA_MESSAGE_EVENT, buildKlarnaMessageEventMap(klarnaProductEvent));
put(PARAM_NAME_KLARNA_MESSAGE_EVENT, eventMap);
}});
postEventForView(KlarnaStandaloneWebViewEvent.Event.ON_KLARNA_MESSAGE, params, view);
}

public void sendRenderProcessGoneEvent(@Nullable KlarnaStandaloneWebView view, boolean didCrash) {
ReadableMap eventMap = ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_DID_CRASH, didCrash);
}});
WritableMap params = ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_RENDER_PROCESS_GONE_EVENT, buildRenderProcessGoneEventMap(didCrash));
put(PARAM_NAME_RENDER_PROCESS_GONE_EVENT, eventMap);
}});
postEventForView(KlarnaStandaloneWebViewEvent.Event.ON_RENDER_PROCESS_GONE, params, view);
}
Expand Down Expand Up @@ -117,37 +122,17 @@ private KlarnaStandaloneWebView getKlarnaStandaloneWebView(@Nullable KlarnaStand
return null;
}

private ReadableMap buildWebViewStateMap(String url, String title, int progress) {
return ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_URL, url);
put(PARAM_NAME_TITLE, title);
put(PARAM_NAME_PROGRESS, String.valueOf(progress));
put(PARAM_NAME_IS_LOADING, progress < 100);
}});
}

private ReadableMap buildNavigationEventMap(@Nullable KlarnaStandaloneWebView view, KlarnaStandaloneWebViewEvent.Event event) {
if (view == null) {
return Arguments.createMap();
} else {
return ArgumentsUtil.createMap(new HashMap<>() {{
// Possible values for 'event' are 'willLoad', 'loadStarted', and 'loadEnded'
put(PARAM_NAME_EVENT, event == KlarnaStandaloneWebViewEvent.Event.ON_LOAD_START ? "loadStarted" : "loadEnded");
put(PARAM_NAME_NEW_URL, view.getUrl());
put(PARAM_NAME_WEB_VIEW_STATE, buildWebViewStateMap(view.getUrl(), view.getTitle(), view.getProgress()));
}});
}
}

private ReadableMap buildKlarnaMessageEventMap(KlarnaProductEvent klarnaProductEvent) {
return ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_ACTION, klarnaProductEvent.getAction());
}});
}

private ReadableMap buildRenderProcessGoneEventMap(boolean didCrash) {
private WritableMap buildWebViewMap(KlarnaStandaloneWebView webView, String url) {
return ArgumentsUtil.createMap(new HashMap<>() {{
put(PARAM_NAME_DID_CRASH, didCrash);
if (webView != null) {
put(PARAM_NAME_URL, url != null ? url : webView.getUrl());
put(PARAM_NAME_TITLE, webView.getTitle());
put(PARAM_NAME_LOADING, webView.getProgress() < 100);
put(PARAM_NAME_CAN_GO_BACK, webView.canGoBack());
put(PARAM_NAME_CAN_GO_FORWARD, webView.canGoForward());
} else {
put(PARAM_NAME_URL, url);
}
}});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,24 @@ public void onError(@NonNull KlarnaComponent klarnaComponent, @NonNull KlarnaMob
private final KlarnaStandaloneWebViewClient klarnaStandaloneWebViewClient = new KlarnaStandaloneWebViewClient() {
@Override
public void onPageStarted(@Nullable KlarnaStandaloneWebView view, @Nullable String url, @Nullable Bitmap favicon) {
klarnaStandaloneWebViewEventSender.sendNavigationEvent(view, KlarnaStandaloneWebViewEvent.Event.ON_LOAD_START);
klarnaStandaloneWebViewEventSender.sendNavigationEvent(view, KlarnaStandaloneWebViewEvent.Event.ON_LOAD_START, url);
}

@Override
public void onPageFinished(@Nullable KlarnaStandaloneWebView view, @Nullable String url) {
klarnaStandaloneWebViewEventSender.sendNavigationEvent(view, KlarnaStandaloneWebViewEvent.Event.ON_LOAD);
klarnaStandaloneWebViewEventSender.sendNavigationEvent(view, KlarnaStandaloneWebViewEvent.Event.ON_LOAD_END, url);
}

@Override
public void onReceivedError(@Nullable KlarnaStandaloneWebView view, @Nullable WebResourceRequest request, @Nullable WebResourceError error) {
if (error != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
klarnaStandaloneWebViewEventSender.sendErrorEvent(view, error.getDescription().toString());
klarnaStandaloneWebViewEventSender.sendErrorEvent(view, error.getErrorCode(), error.getDescription().toString());
}
}

@Override
public void onReceivedError(@Nullable KlarnaStandaloneWebView view, int errorCode, @Nullable String description, @Nullable String failingUrl) {
klarnaStandaloneWebViewEventSender.sendErrorEvent(view, description);
klarnaStandaloneWebViewEventSender.sendErrorEvent(view, errorCode, description);
}

@Override
Expand Down Expand Up @@ -174,7 +174,7 @@ public void reload(KlarnaStandaloneWebView view) {
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
MapBuilder.Builder<String, Object> builder = MapBuilder.builder();
builder.put(KlarnaStandaloneWebViewEvent.Event.ON_LOAD_START.name, MapBuilder.of("registrationName", KlarnaStandaloneWebViewEvent.Event.ON_LOAD_START.name));
builder.put(KlarnaStandaloneWebViewEvent.Event.ON_LOAD.name, MapBuilder.of("registrationName", KlarnaStandaloneWebViewEvent.Event.ON_LOAD.name));
builder.put(KlarnaStandaloneWebViewEvent.Event.ON_LOAD_END.name, MapBuilder.of("registrationName", KlarnaStandaloneWebViewEvent.Event.ON_LOAD_END.name));
builder.put(KlarnaStandaloneWebViewEvent.Event.ON_ERROR.name, MapBuilder.of("registrationName", KlarnaStandaloneWebViewEvent.Event.ON_ERROR.name));
builder.put(KlarnaStandaloneWebViewEvent.Event.ON_LOAD_PROGRESS.name, MapBuilder.of("registrationName", KlarnaStandaloneWebViewEvent.Event.ON_LOAD_PROGRESS.name));
builder.put(KlarnaStandaloneWebViewEvent.Event.ON_KLARNA_MESSAGE.name, MapBuilder.of("registrationName", KlarnaStandaloneWebViewEvent.Event.ON_KLARNA_MESSAGE.name));
Expand Down
2 changes: 1 addition & 1 deletion ios/Sources/KlarnaStandaloneWebViewManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ @implementation KlarnaStandaloneWebViewManager

RCT_EXPORT_VIEW_PROPERTY(returnUrl, NSString)
RCT_EXPORT_VIEW_PROPERTY(onLoadStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadEnd, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadProgress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onKlarnaMessage, RCTDirectEventBlock)
Expand Down
68 changes: 36 additions & 32 deletions ios/Sources/view/newarch/KlarnaStandaloneWebViewWrapper.mm
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,26 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
NSNumber * newProgress = [change objectForKey:NSKeyValueChangeNewKey];
// We need to convert it to an int value in range [0..100]
int progress = [NSNumber numberWithDouble:(newProgress.doubleValue * 100)].intValue;
[self sendProgressChangeEvent:progress];
[self sendLoadProgressEvent:progress];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

- (void)sendProgressChangeEvent:(int)progress {
- (void)sendLoadProgressEvent:(int)progress {
if (_eventEmitter) {
RCTLogInfo(@"Sending onLoadProgress event");
NSString * url = self.klarnaStandaloneWebView.url == nil ? @"" : self.klarnaStandaloneWebView.url.absoluteString;
NSString * title = self.klarnaStandaloneWebView.title == nil ? @"" : self.klarnaStandaloneWebView.title;
std::dynamic_pointer_cast<const RNKlarnaStandaloneWebViewEventEmitter>(_eventEmitter)
->onLoadProgress(RNKlarnaStandaloneWebViewEventEmitter::OnLoadProgress{
.progressEvent = {
.webViewState = {
.url = std::string([url UTF8String]),
.title = std::string([title UTF8String]),
.progress = std::string([[@(progress) stringValue] UTF8String]),
.isLoading = self.klarnaStandaloneWebView.isLoading,
}
.url = std::string([url UTF8String]),
.title = std::string([title UTF8String]),
.loading = self.klarnaStandaloneWebView.isLoading,
.canGoBack = self.klarnaStandaloneWebView.canGoBack,
.canGoForward = self.klarnaStandaloneWebView.canGoForward,
.progress = (double)progress
}
});
} else {
Expand Down Expand Up @@ -142,18 +142,14 @@ - (void)klarnaStandaloneWebView:(KlarnaStandaloneWebView * _Nonnull)webView didC
RCTLogInfo(@"Sending onLoadStart event");
// 'estimatedProgress' is a double value in range [0..1].
// We need to convert it to an int value in range [0..100].
int progress = (int) (self.klarnaStandaloneWebView.estimatedProgress * 100);
std::dynamic_pointer_cast<const RNKlarnaStandaloneWebViewEventEmitter>(_eventEmitter)
->onLoadStart(RNKlarnaStandaloneWebViewEventEmitter::OnLoadStart{
.navigationEvent = {
.event = facebook::react::RNKlarnaStandaloneWebViewEventEmitter::OnLoadStartNavigationEventEvent::LoadStarted,
.newUrl = std::string([webView.url.absoluteString UTF8String]),
.webViewState = {
.url = std::string([webView.url.absoluteString UTF8String]),
.title = std::string([webView.title UTF8String]),
.progress = std::string([[@(progress) stringValue] UTF8String]),
.isLoading = webView.isLoading,
}
.url = std::string([webView.url.absoluteString UTF8String]),
.title = std::string([webView.title UTF8String]),
.loading = self.klarnaStandaloneWebView.isLoading,
.canGoBack = self.klarnaStandaloneWebView.canGoBack,
.canGoForward = self.klarnaStandaloneWebView.canGoForward,
}
});
} else {
Expand All @@ -163,21 +159,17 @@ - (void)klarnaStandaloneWebView:(KlarnaStandaloneWebView * _Nonnull)webView didC

- (void)klarnaStandaloneWebView:(KlarnaStandaloneWebView * _Nonnull)webView didFinish:(WKNavigation * _Nonnull)navigation {
if (_eventEmitter) {
RCTLogInfo(@"Sending onLoad event");
RCTLogInfo(@"Sending onLoadEnd event");
// 'estimatedProgress' is a double value in range [0..1].
// We need to convert it to an int value in range [0..100].
int progress = (int) (self.klarnaStandaloneWebView.estimatedProgress * 100);
std::dynamic_pointer_cast<const RNKlarnaStandaloneWebViewEventEmitter>(_eventEmitter)
->onLoad(RNKlarnaStandaloneWebViewEventEmitter::OnLoad{
->onLoadEnd(RNKlarnaStandaloneWebViewEventEmitter::OnLoadEnd{
.navigationEvent = {
.event = facebook::react::RNKlarnaStandaloneWebViewEventEmitter::OnLoadNavigationEventEvent::LoadEnded,
.newUrl = std::string([webView.url.absoluteString UTF8String]),
.webViewState = {
.url = std::string([webView.url.absoluteString UTF8String]),
.title = std::string([webView.title UTF8String]),
.progress = std::string([[@(progress) stringValue] UTF8String]),
.isLoading = webView.isLoading,
}
.url = std::string([webView.url.absoluteString UTF8String]),
.title = std::string([webView.title UTF8String]),
.loading = self.klarnaStandaloneWebView.isLoading,
.canGoBack = self.klarnaStandaloneWebView.canGoBack,
.canGoForward = self.klarnaStandaloneWebView.canGoForward,
}
});
} else {
Expand All @@ -190,8 +182,14 @@ - (void)klarnaStandaloneWebView:(KlarnaStandaloneWebView * _Nonnull)webView didF
RCTLogInfo(@"Sending onError event");
std::dynamic_pointer_cast<const RNKlarnaStandaloneWebViewEventEmitter>(_eventEmitter)
->onError(RNKlarnaStandaloneWebViewEventEmitter::OnError{
.navigationError = {
.errorMessage = std::string([[error localizedDescription] UTF8String]),
.error = {
.url = std::string([webView.url.absoluteString UTF8String]),
.title = std::string([webView.title UTF8String]),
.loading = self.klarnaStandaloneWebView.isLoading,
.canGoBack = self.klarnaStandaloneWebView.canGoBack,
.canGoForward = self.klarnaStandaloneWebView.canGoForward,
.code = (int)error.code,
.description = std::string([[error localizedDescription] UTF8String])
}
});
} else {
Expand All @@ -204,8 +202,14 @@ - (void)klarnaStandaloneWebView:(KlarnaStandaloneWebView * _Nonnull)webView didF
RCTLogInfo(@"Sending onError event");
std::dynamic_pointer_cast<const RNKlarnaStandaloneWebViewEventEmitter>(_eventEmitter)
->onError(RNKlarnaStandaloneWebViewEventEmitter::OnError{
.navigationError = {
.errorMessage = std::string([[error localizedDescription] UTF8String]),
.error = {
.url = std::string([webView.url.absoluteString UTF8String]),
.title = std::string([webView.title UTF8String]),
.loading = self.klarnaStandaloneWebView.isLoading,
.canGoBack = self.klarnaStandaloneWebView.canGoBack,
.canGoForward = self.klarnaStandaloneWebView.canGoForward,
.code = (int)error.code,
.description = std::string([[error localizedDescription] UTF8String])
}
});
} else {
Expand Down
2 changes: 1 addition & 1 deletion ios/Sources/view/oldarch/KlarnaStandaloneWebViewWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface KlarnaStandaloneWebViewWrapper : UIView

@property (nonatomic, copy) RCTDirectEventBlock onLoadStart;
@property (nonatomic, copy) RCTDirectEventBlock onLoad;
@property (nonatomic, copy) RCTDirectEventBlock onLoadEnd;
@property (nonatomic, copy) RCTDirectEventBlock onError;
@property (nonatomic, copy) RCTDirectEventBlock onLoadProgress;
@property (nonatomic, copy) RCTDirectEventBlock onKlarnaMessage;
Expand Down
Loading

0 comments on commit 0e52a4b

Please sign in to comment.