Flutter webview PayPal intergation error? - flutter

I want to integrate PayPal buttons like this:
https://developer.paypal.com/demo/checkout/#/pattern/client
I put this sample code in a HTML file (assets/paypal.html), and read from assets into the WebView:
#override
Widget build(BuildContext context) {
return Scaffold(
body: WebView(
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
_loadHtml();
},
),
);
}
void _loadHtml() async {
String fileText = await rootBundle.loadString('assets/paypal.html');
_controller!.loadUrl(Uri.dataFromString(fileText, mimeType: 'text/html', encoding: Encoding.getByName('utf-8')).toString());
}
But I get this error (Uncaught Error: Bootstrap Error for buttons):
[INFO:CONSOLE(2)] "insertPPTM [object Object]", source: https://www.paypal.com/sdk/js?client-id=test&currency=USD (2) [INFO:CONSOLE(2)] "Uncaught Error: Bootstrap Error for buttons:
Can not read window host
Error: Can not read window host
at j (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:18528)
at B (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:18625)
at zt (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:58764)
at Cu (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:288789)
at Object.__get__ (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:288874)
at o (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:291801)
at https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:291984
at Module.<anonymous> (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:292214)
at t (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:157)
at https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:941", source: https://www.paypal.com/sdk/js?client-id=test&currency=USD (2) [INFO:CONSOLE(2)] "Uncaught Error: Bootstrap Error for common:
Can not read window host
Error: Can not read window host
at j (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:18528)
at B (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:18625)
at zt (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:58764)
at Iu (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:289405)
at Object.__get__ (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:289453)
at o (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:291801)
at https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:291984
at Module.<anonymous> (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:292214)
at t (https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:157)
at https://www.paypal.com/sdk/js?client-id=test&currency=USD:2:941", source: https://www.paypal.com/sdk/js?client-id=test&currency=USD (2) [INFO:CONSOLE(2)] "unhandled_error [object Object]", source: https://www.paypal.com/sdk/js?client-id=test&currency=USD (2) [INFO:CONSOLE(2)] "unhandled_error [object Object]", source: https://www.paypal.com/sdk/js?client-id=test&currency=USD (2) [INFO:CONSOLE(2)] "Uncaught Error: Can not read window host", source: https://www.paypal.com/sdk/js?client-id=test&currency=USD (2) [INFO:CONSOLE(2)] "Uncaught Error: Can not read window host", source: https://www.paypal.com/sdk/js?client-id=test&currency=USD (2)
I tried 2 flutter WebView plugins, same error ( webview_flutter 2.0.10 , flutter_webview_plugin 0.4.0 )

PayPal cannot be used from webviews, as the documentation explains.
Do not use a WebView to display PayPal web pages within your
application
Your application must not use a WebView or similar custom browser
mechanism for display of PayPal web pages. Instead, use an appropriate
PayPal SDK to manage the PayPal experience or launch the PayPal web
page within the system browser or an approved browser-view mechanism
such as Safari View Controller on iOS or Chrome Custom Tabs on
Android.

Related

Flutter web: The communication between Flutter web and Flutter APP fails

APP : Developed with Flutter
Web: Develop with Flutter
Use the webview_flutter plugin to load web pages in app.
Now the web page wants to communicate with the APP.
It is possible to use JavaScript methods to interact with flutter.
JavaScript code
function toast() {
Toast.postMessage("message from web page");
}
Flutter APP code
JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toast',
onMessageReceived: (JavascriptMessage message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message.message)),
);
});
}
The above method is possible.
But now Flutter web tries to interact with Flutter APP and fails, code show as below
Flutter web code
void toast() {
html.window.postMessage("message from web page", "Toast");
}
Flutter APP code same as above.
The error message is as follows
I/chromium(25735): [INFO:CONSOLE(14560)] "SyntaxError: Failed to
execute 'postMessage' on 'Window': Invalid target origin 'Toast' in a
call to 'postMessage'."
Is there something wrong with my calling method?
There's a way, but it doesn't feel good.
Define a JavaScript file in the web directory, here called toast.js. This file defines the methods to communicate with Dart.
function makeToast(msg) {
Toast.postMessage(msg);
}
Import toast.js in index.html in the web directory
<head>
// ...
<!-- This script adds the flutter initialization JS code -->
<script src="flutter.js" defer></script>
<!-- new line -->
<script src="toast.js"></script>
</head>
Go back to the Flutter project and create a dart file in the lib directory, called js_channel.dart here, declare a method in this file for Dart to call JavaScript methods
import 'package:js/js.dart';
#JS('makeToast')
external void makeToast(String msg);
Call makeToast method
void toast() {
makeToast("msg from flutter web")
}
The above steps are all done in the flutter web project.
Next, you need to use the webview in the Flutter native (android or ios) project to load the web page built by the Flutter web project, and then listen to the message sent by the Toast object in the webview.
Here I am using the webview_flutter plugin
Widget _buildWebView() {
return WebView(
debuggingEnabled: true,
initialUrl: "your web url",
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: <JavascriptChannel>{
JavascriptChannel(
name: 'Toast',
onMessageReceived: (JavascriptMessage message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message.message)),
);
},
),
},
),
}

Google Actions: Testing Library complains about Firebase Terms

I'm trying to implement tests for my Google Action with Assistant Conversation Testing Library.
The problem is that the execution is complaining about: "Firebase Terms of Service is not accepted". I can't find any way to accept these terms - neither in the Actions Console or in the Cloud Platform.
It was working ~two weeks ago and suddenly it stoped working with this error. As far as I know I haven't changed anything related. I also tried creating a new service_account.json, but this didn't help.
Error message/stacktrace:
Starting writePreview From Draft
Error: 9 FAILED_PRECONDITION: Firebase Terms of Service is not accepted. Navigate to your project's overview page on the Actions Console to accept the Terms of Service.
at Object.callErrorFromStatus (test/node_modules/#grpc/grpc-js/build/src/call.js:31:26)
at Object.onReceiveStatus (test/node_modules/#grpc/grpc-js/build/src/client.js:244:52)
at Object.onReceiveStatus (test/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:334:141)
at Object.onReceiveStatus (test/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:297:181)
at test/node_modules/#grpc/grpc-js/build/src/call-stream.js:130:78
at processTicksAndRejections (internal/process/task_queues.js:75:11) {
code: 9,
details: "Firebase Terms of Service is not accepted. Navigate to your project's overview page on the Actions Console to accept the Terms of Service.",
metadata: Metadata {
internalRepr: Map(2) {
'google.rpc.preconditionfailure-bin' => [Array],
'grpc-status-details-bin' => [Array]
},
options: {}
}
}
Source Code:
const { ActionsOnGoogleTestManager } = require('#assistant/conversation-testing');
async function openAction(projectId, invocationName) {
const testManager = new ActionsOnGoogleTestManager({ projectId: projectId });
testManager.setTestSurface('SMART_DISPLAY');
testManager.setSuiteLocale("en-US")
await testManager.writePreviewFromDraft();
await testManager.sendQuery(`Talk to ${invocationName}`);
testManager.assertText("Hello World")
testManager.assertIntent('actions.intent.MAIN');
}

SSO on Microsoft Edge not working but does work on IE11, Chrome, Safari, Firefox - via Office.js add-in

The following oAuth2 SSO code in my Office.js addin application works great in IE11, Chrome, Safari and Firefox, but doesn't work in Microsoft Edge. I can see the bearer token is being returned to the pop-up dialog via the url:
https://localhost:3000/login?access_token=ya29.ImG6By-0ZWPQB4MsYxxxxxxxxxxxxxxxxxxxxxxxxxxxxE5XsM9v7SBi-OaUBBQucO05luKVP0pYoSrcYzbaUKAAX&token_type=Bearer
I can also see that the asyncResult.status == succeeded, i.e.
[object Object]: {status: "succeeded", value: Object}
status: "succeeded"
value: Object
addEventHandler: function (){var d=OSF.DDA.SyncMethodCalls[OSF.DDA.SyncMethodNames.AddMessageHandler.id],c=d.verifyAndExtractCall(arguments,a,b),e=c[Microsoft.Office.WebExtension.Parameters.EventType],f=c[Microsoft.Office.WebExtension.Parameters.Handler];return b.addEventHandlerAndFireQueuedEvent(e,f)}
arguments: null
caller: null
length: 0
name: "value"
prototype: Object
proto: function() { [native code] }
close: function (){var c=OSF._OfficeAppFactory.getHostFacade()[OSF.DDA.DispIdHost.Methods.CloseDialog];c(arguments,g,b,a)}
sendMessage: function (){var c=OSF._OfficeAppFactory.getHostFacade()[OSF.DDA.DispIdHost.Methods.SendMessage];return c(arguments,b,a)}
proto: Object
proto: Object
However, the "console.log('hello');" doesn't get called when Microsoft Edge is running the sidebar/add-in.
The pop-up dialog is showing this in the F12 debug console:
HTTP403: FORBIDDEN - The server understood the request, but is refusing to fulfill it.
(XHR)POST - https://browser.pipe.aria.microsoft.com/Collector/3.0/?qsp=true&content-type=application%2Fbond-compact-binary&client-id=NO_AUTH&sdk-version=AWT-Web-JS-1.1.1&x-apikey=a387cfcf60114a43a7699f9fbb49289e-9bceb9fe-1c06-460f-96c5-6a0b247358bc-7238&client-time-epoch-millis=1579626709267&time-delta-to-apply-millis=961
Any ideas?
export function loginUsingOAuth() {
try {
const sealUrl = getFromStorage('seal_url', STORAGE_TYPE.LOCAL_STORAGE);
const redirectUrl = `${window.location.protocol}//${window.location.host}/login`;
let displayInIframe = false;
let promptBeforeOpen = false;
if (typeof sealUrl !== 'undefined' && sealUrl) {
const oAuthUrl = `${sealUrl}/seal-ws/oauth2/login?redirect_uri=${redirectUrl}`;
Office.context.ui.displayDialogAsync(
oAuthUrl,
{
height: 80,
width: 80,
displayInIframe,
promptBeforeOpen
},
asyncResult => {
console.log('asyncResult');
console.log(asyncResult);
addLog(LOG_TYPE.INFO, 'authentication.loginUsingOAuth', asyncResult);
if (asyncResult.status !== 'failed') {
const dialog = asyncResult.value;
dialog.addEventHandler(Office.EventType.DialogMessageReceived, args => {
console.log('hello');
Maybe this is actually a routing issue when executing in Edge? The "/login" callback is routed to the AuthCallback.js component:
const Routes = () => (
<BrowserRouter>
<Switch>
<Route exact path="/login" component={AuthCallback} />
<Route path="/" component={BaseLayout} />
</Switch>
</BrowserRouter>
);
The constructor of the AuthCallback.js component calls messageParent after a short pause:
constructor(props) {
super(props);
const paramsObj = queryString.parse(props.location.search);
const paramsStr = JSON.stringify(paramsObj);
setTimeout(() => {
Office.context.ui.messageParent(paramsStr);
}, 1200);
}
I'm starting to wonder if Edge is messing with the redirect. In the image below you can see that IE and Edge are returning different status codes for the same sign-on operation:
There seems to be two problems with the Edge browser.
The redirect/callback is not calling the components constructor when displayInIframe=false when running on Microsoft Edge. All other browsers work as expected. I've added conditional logic to set displayInIframe=true for the Edge browser use-case
The messageParent method also does not work for the Edge browser when displayInIframe=true. Therefore I've had to extract the auth token in the pop-up dialog callback and stash it away in the local_storage. The parent (the sidebar) is then polling the local_storage to detect that the sign-in has completed. Again, Chrome, Firefox, Safari, IE11 (both Mac and PC) are all fine - its just the Edge browser that is failing.
Whilst this is an ugly solution to the problem it is also imperfect because IF the end-user is not already signed-in to SSO then the Google [Account Selector] dialog is shown, which is a problem when displayInIframe=true as this throws an iframe exception.
I don't see any other option open to us, because the O/S build number and MSWord version dictates which browser is used to render the sidebar. The inability to choose whether IE11 or Edge is used would be bearable if Edge didn't have these functional deficits.

Unable to switch from hybrid app to com.mobile.safari with Appium & Protractor

I have an ionic/angularjs/cordova application that uses the cordova facebook plugin. I have appium with cucumber and protractor setup and I can test everything on the app within the simulator. In the app itself I have facebook authentication setup and I am trying to test this on an iOS simulator.
If you look at this step below
And I input my facebook credentials
The app will redirect to facebook mobile web, waits for the browser to load and then will infinitely refresh itself.
When I console.log the browser url after the cordova app redirects to facebook on safari, the url is the app's local file path and now the browser url of facebook.
config.js
exports.config = {
capabilities: {
browserName: 'iOS',
app: '/Users/username/Projects/app-directory/platforms/ios/build/emulator/appname.app',
deviceName: 'iPhone Simulator',
'appium-version': '1.3.0-beta1',
version: '8.0',
platformName: 'iOS',
platformVersion: '8.0',
autoWebview: true,
autoWebviewTimeout: 10
},
allScriptsTimeout: 30000,
seleniumAddress: 'http://localhost:4723/wd/hub',
baseUrl: 'http://localhost:8100',
onPrepare: function() {
var wd = require('wd'),
_ = require('underscore'),
wdBridge = require('wd-bridge')(protractor, wd);
wdBridge.initFromProtractor(exports.config);
},
framework: 'cucumber',
cucumberOpts: {
require: '../features/**/*.js',
format: 'pretty'
},
specs: [ '../features/*.feature' ]
};
root.feature
Feature: Root Screen
As a user who is not logged in
I want to be greeted with a menu screen
So that I know where to sign up or login
Scenario: Successfully logging into the app through facebook
Given I am a user on facebook
When I click on the facebook button
And I input my facebook credentials
And I accept the facebook permissions
Then I should be at the home screen
root steps
var rootSteps = function() {
this.Given(/^I am a user on facebook$/, function (done) {
this.app.createFbUser().then(done); // helper that returns a promise and creates a fb test user object and sets it to this.app.fbUser;
});
this.When(/^I click on the facebook button$/, function (done) {
browser.driver.findElement(by.css('[ng-click="fbLogin()"]')).click().then(done);
});
this.When(/^I input my facebook credentials$/, function (done) {
browser.sleep( 8000 ); // wait for facebook to completely load
wdBrowser.contexts().then(function(ctxs) {
var webCtx = _(ctxs).find(function(ctx) { return ctx.match(/WEBVIEW/)});
wdBrowser.context(webCtx) ;
}).then(function() {
browser.ignoreSynchronization = true
var emailElem = browser.driver.findElement(by.name('email'));
var passwordElem = browser.driver.findElement(by.name('password'));
var submitElem = browser.driver.findElement(by.name('login'));
emailElem.sendKeys(this.app.fbUser.email);
passwordElem.sendKeys(this.app.fbUser.password);
submitElem.click().then(done);
});
});
this.When(/^I accept the facebook permissions$/, function (done) {
done.pending();
});
this.Then(/^I should be at the home screen$/, function (done) {
done.pending();
})
};
module.exports = rootSteps;
Here is the error logs from Appium.
info: [debug] Responding to client with success: {"status":0,"value":["NATIVE_APP","WEBVIEW_1"],"sessionId":"a93509a3-3cce-4f03-be58-c59474b40e92"}
info: <-- GET /wd/hub/session/a93509a3-3cce-4f03-be58-c59474b40e92/contexts 200 2.140 ms - 98 {"status":0,"value":["NATIVE_APP","WEBVIEW_1"],"sessionId":"a93509a3-3cce-4f03-be58-c59474b40e92"}
info: [debug] [REMOTE] Receiving data from remote debugger
info: [debug] [REMOTE] got applicationSentData response
info: [debug] [REMOTE] Got a blank data response from debugger
info: [debug] [REMOTE] Receiving data from remote debugger
info: [debug] [REMOTE] Receiving data from remote debugger
info: [debug] [REMOTE] {"__argument" {"WIRApplicationIdentifierKey":"PID:34459","WIRIsApplicationProxyKey":false,"WIRApplicationNameKey":"Safari","WIRApplicationBundleIdentifierKey":"com.apple.mobilesafari","WIRIsApplicationActiveKey":1},"__selector":"_rpc_applicationConnected:"}
info: [REMOTE] We were notified that we connected to possibly the wrong application. Ignoring for now and hoping we're going to retry looking for apps
Right now this is currently not possible. According to the Appium team, xcode instruments loads up the app and currently can not change the bundle id.

Facebook share via app loads two popups

The problem can be watched here
http://antipinagroup.com/collections/sac-de-voyage
On sharing via fb app ui loads two popups — feed dialogue and blank page.
Can't get the problem. Any ideas why it happens and how to resolve it?
The code for forming
objFB = {
method: 'feed',
link: document.location.href,
picture: fullPathImage + numimg +".jpg",
name: dataBl.title,
caption: dataBl.title,
description: dataBl['text description']};
_share = _share.replace(/href="javascript:;"/g, 'onclick="postToFeed(); return false;"' );
$( "." + mainBlockClass + " #overlay_" + mainBlockClass ).html( _share );
break;}});
(function(d){FB.init({appId: "151107748411463", status: true, cookie: true});}(document));
function postToFeed() { function callback(response) { /*console.log(response);*/ }FB.ui(objFB, callback);}
All I’m getting when I’m trying you FB share is
An error occurred. Please try again later.
API Error Code: 1
API Error Description: An unknown error occurred
Error Message: kError 1349040: Invalid App ID: The provided app ID is invalid.
I added &show_error=true at the end of the feed dialog URL your page creates as you can see, which is always (OK, make that most of the times) helpful to find errors with FB dialogs.
So first of all check your app id in your code.