I have created a bot locally using bot framework v4 c#. It has a welcome card that automatically pops up as soon I connect my local url with emulator, but recently I deployed my bot on azure and integrated it using direct line channel in my website. Now whenever I click, it opens the bot but the welcome card does not come on its own ,it appears when I write something from my chatbot. I just want the welcome card to appaer automatically as it appears in the emulator. Guys can you help me out please? Below is the code of direct line which I am integrating in my website.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<!-- Paste line 7 to 27 after the title tag in _Layout.cshtml -->
<link href="https://cdn.botframework.com/botframework-webchat/latest/botchat.css" rel="stylesheet"
/>
<script src="https://cdn.botframework.com/botframework-webchat/latest/botchat.js"></script>
<style>
#mychat {
margin: 10px;
position: fixed;
bottom: 30px;
left: 10px;
z-index: 1000000;
}
.botIcon {
float: left !important;
border-radius: 50%;
}
.userIcon {
float: right !important;
border-radius: 50%;
}
</style>
</head>
< body>
<!-- Paste line from 31 to 33 before the </body> tag at the end of code -->
<div id="container">
<img id="mychat" src=""/>
</div>
</body>
<!-- Paste line 38 to 88 after the </html> tag -->
<script>
(function () {
var div = document.createElement("div");
var user = {
id: "",
name: ''
};
var bot = {
id: '',
name: 'SaathiBot'
};
const botConnection = new BotChat.DirectLine({
secret: '',
webSocket: false
})
document.getElementsByTagName('body')[0].appendChild(div);
div.outerHTML = "<div id='botDiv' style='width: 400px; height: 0px; margin:10px; position:
fixed; bottom: 0; left:0; z-index: 1000;><div id='botTitleBar' style='height: 40px; width: 400px;
position:fixed; cursor: pointer;'>";
BotChat.App({
botConnection: botConnection,
user: user,
bot: bot
}, document.getElementById("botDiv"));
document.getElementsByClassName("wc-header")[0].setAttribute("id", "chatbotheader");
document.querySelector('body').addEventListener('click', function (e) {
e.target.matches = e.target.matches || e.target.msMatchesSelector;
if (e.target.matches('#chatbotheader')) {
var botDiv = document.querySelector('#botDiv');
botDiv.style.height = "0px";
document.getElementById("mychat").style.display = "block";
};
});
document.getElementById("mychat").addEventListener("click", function (e) {
document.getElementById("botDiv").style.height = '500px';
e.target.style.display = "none";
})
}());
</script>
Also here is my welcome card code in c#
namespace Microsoft.BotBuilderSamples
{
public class WelcomeUser : SaathiDialogBot<MainDialog>
{
protected readonly string[] _cards =
{
Path.Combine(".", "Resources", "WelcomeCard.json"),
};
public WelcomeUser(ConversationState conversationState, UserState userState, MainDialog dialog, ILogger<SaathiDialogBot<MainDialog>> logger)
: base(conversationState, userState, dialog, logger)
{
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
await SendWelcomeMessageAsync(turnContext, cancellationToken);
Random r = new Random();
var cardAttachment = CreateAdaptiveCardAttachment(_cards[r.Next(_cards.Length)]);
await turnContext.SendActivityAsync(MessageFactory.Attachment(cardAttachment), cancellationToken);
}
private static async Task SendWelcomeMessageAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
foreach (var member in turnContext.Activity.MembersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
if (DateTime.Now.Hour < 12)
{
await turnContext.SendActivityAsync(
$"Hi,Good Morning {member.Name}",
cancellationToken: cancellationToken);
}
else if (DateTime.Now.Hour < 17)
{
await turnContext.SendActivityAsync(
$"Hi,Good Afternoon {member.Name}",
cancellationToken: cancellationToken);
}
else
{
await turnContext.SendActivityAsync(
$"Hi,Good Evening {member.Name}",
cancellationToken: cancellationToken);
}
}
}
}
private static Attachment CreateAdaptiveCardAttachment(string filePath)
{
var adaptiveCardJson = File.ReadAllText(filePath);
var adaptiveCardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCardJson),
};
return adaptiveCardAttachment;
}
}
}
Here the saathiDialog code which inherited in welcome card. These are the two files inside my bot folder
namespace Microsoft.BotBuilderSamples
{
public class SaathiDialogBot<T> : ActivityHandler where T : Dialog
{
protected readonly BotState ConversationState;
protected readonly Dialog Dialog;
protected readonly ILogger Logger;
protected readonly BotState UserState;
private DialogSet Dialogs { get; set; }
public SaathiDialogBot(ConversationState conversationState, UserState userState, T dialog, ILogger<SaathiDialogBot<T>> logger)
{
ConversationState = conversationState;
UserState = userState;
Dialog = dialog;
Logger = logger;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
var activity = turnContext.Activity;
if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
{
activity.Text = JsonConvert.SerializeObject(activity.Value);
}
if (turnContext.Activity.Text == "Yes")
{
await turnContext.SendActivityAsync($"Good bye. I will be here if you need me. ", cancellationToken: cancellationToken);
await turnContext.SendActivityAsync($"Say Hi to wake me up.", cancellationToken: cancellationToken);
}
else
{
await base.OnTurnAsync(turnContext, cancellationToken);
}
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
Logger.LogInformation("Running dialog with Message Activity.");
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}
}
}
If you are using WebChat or directline, the bot’s ConversationUpdate is sent when the conversation is created and the user sides’ ConversationUpdate is sent when they first send a message. When ConversationUpdate is initially sent, there isn’t enough information in the message to construct the dialog stack. The reason that this appears to work in the emulator, is that the emulator simulates a sort of pseudo DirectLine, but both conversationUpdates are resolved at the same time in the emulator, and this is not the case for how the actual service performs.
A workaround would be to send a back channel welcome event to the bot when the DirectLine connection is established and send a welcome message from the onEventAsync handler instead of onMembersAdded.
Embedded HTML for Web Chat
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<style>
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div style="display: flex">
<div style="position: relative; height: 500px; width: 500px"><div id="bot" ></div></div>
</div>
<script>
(async function() {
const res = await fetch('/directline/token', { method: 'POST' });
const { token } = await res.json();
var userinfo = {
id: 'user-id',
name: 'user name',
locale: 'es'
};
var botConnection = new window.BotChat.DirectLine({ token });
botConnection.connectionStatus$
.subscribe(connectionStatus => {
switch(connectionStatus) {
case window.BotChat.ConnectionStatus.Online:
botConnection.postActivity({
from: { id: 'myUserId', name: 'myUserName' },
type: 'event',
name: 'webchat/join',
value: { locale: 'en-US' }
}).subscribe(
id => console.log("Posted welcome event, assigned ID ", id),
error => console.log("Error posting activity", error)
);
break;
}
});
BotChat.App({
botConnection: botConnection,
user: userinfo,
bot: { id: 'botid' },
resize: 'detect'
}, document.getElementById("bot"));
})().catch(err => console.log(err));
</script>
</body>
</html>
Bot Code in C#
protected override async Task OnEventActivityAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.Name == "webchat/join") {
await turnContext.SendActivityAsync("Welcome Message!");
}
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.ChannelId != "webchat" && turnContext.Activity.ChannelId != "directline") {
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync($"Hi there - {member.Name}. {WelcomeMessage}", cancellationToken: cancellationToken);
await turnContext.SendActivityAsync(InfoMessage, cancellationToken: cancellationToken);
await turnContext.SendActivityAsync(PatternMessage, cancellationToken: cancellationToken);
}
}
}
}
Hope this helps.
Send a custom event activity.
For more information, please check this link
Related
Stripe Checkout in webView flutter app
Integrating Stripe checkout with Flutter mobile app. Worked with this in previous versions of Flutter & webview_flutter plugin.
But now it's showing this error in the console and stuck the webView at initial URL:
I/chromium(26312): [INFO:CONSOLE(1)] "Stripe.js requires 'allow-same-origin' if sandboxed.", source: https://js.stripe.com/v3/ (1)
I/chromium(26312): [INFO:CONSOLE(1)] "Uncaught SecurityError: Failed to read the 'cookie' property from 'Document': Cookies are disabled inside 'data:' URLs.", source: https://js.stripe.com/v3/ (1)
Flutter Code for Webview Stripe Checkout
class StripePaymentCheckout extends StatefulWidget {
final String sessionId;
const StripePaymentCheckout({Key key, this.sessionId}) : super(key: key);
#override
_StripePaymentCheckoutState createState() => _StripePaymentCheckoutState();
}
class _StripePaymentCheckoutState extends State<StripePaymentCheckout> {
WebViewController _webViewController;
String get initialUrl =>
"data:text/html;base64,${base64Encode(const Utf8Encoder().convert(kStripeHTMLPage))}";
static const String kStripeHTMLPage = '''
<!DOCTYPE html>
<html>
<script src="https://js.stripe.com/v3/"></script>
<head>
<title>Stripe Checkout</title>
</head>
<body>
<div style="position: absolute; text-align: center; width:100%; height:100%; top:50%;">
<h1>Loading Stripe...!</h1>
</div>
</body>
</html>
''';
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: SafeArea(
child: WebView(
initialCookies: [
WebViewCookie(
name: 'sessionid',
value: widget.sessionId,
domain: 'https://js.stripe.com/v3/', // <-- not sure what to do here.
),
],
initialUrl: initialUrl,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (webViewController) {
_webViewController = webViewController;
},
onPageFinished: (String url) {
if (url == initialUrl) {
_redirectToStripe(widget.sessionId);
}
},
navigationDelegate: (NavigationRequest request) {
if (request.url.startsWith('https://success.com')) {
Navigator.of(context).pop("success");
} else if (request.url.startsWith('https://cancel.com')) {
Navigator.of(context).pop('cancel');
}
return NavigationDecision.navigate;
},
),
),
);
}
Future<void> _redirectToStripe(String sessionId) async {
final redirectToCheckoutJs = '''
var stripe = Stripe('${dotenv.env['apiKey']}');
stripe.redirectToCheckout({
sessionId: '$sessionId'
}).then(function (result) {
result.error.message = 'Error'
});
''';
return await _webViewController
.runJavascriptReturningResult(redirectToCheckoutJs);
}
}
the code:
<!DOCTYPE html>
<html>
<script src="https://js.stripe.com/v3/"></script>
<head>
<title>Stripe Checkout</title>
</head>
<body>
<div style="position: absolute; text-align: center; width:100%; height:100%; top:50%;">
<h1>Loading Stripe...!</h1>
</div>
</body>
</html>
need to be deployed on an https for your code to work.
there's a guy who presented the same problem and solved with code you can find here:
https://github.com/MarcinusX/flutter_stripe_demo/blob/master/lib/checkout/stripe_checkout_mobile.dart
and he already hosted the needed code on:
https://marcinusx.github.io/test1/index.html
I am developing one PWA of the ionic capacitor and there is a requirement to load another website in an iframe so from one of the ionic app component I called another site.
iframe.page.html
<ion-header>
<ion-toolbar>
<ion-buttons slot="end" (click)="goBack()">
Close
<ion-icon slot="icon-only" name="close-outline"></ion-icon>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<iframe #iframe height="100%" width="100%" title="test"></iframe>
</ion-content>
iframe.page.ts
export class IframePage implements OnInit, AfterViewInit {
userId = localStorage.getItem('userId');
gameData: any;
gameUrl: any;
docId;
#ViewChild('iframe') iframe: ElementRef;
constructor(private navCtrl: NavController,
private authSrv: AuthService,
private commanSrv: CommannService,
private router:Router) {
firebase.analytics().logEvent('Web_game');
this.iframe.nativeElement.setAttribute('src', 'anotherdomain.com?UID=sadsajdhsakjhdasjhkjsd');
window.addEventListener('message', (event) => {
console.log(event.data);
if (event.data.res === 'win') {
// let routename = commanSrv.getLastRoute();
// navCtrl.navigateForward(routename || 'home_tab');
this.router.navigate(['arcade-outcome', { type: 'arcade_win' }]);
} else if (event.data.res === 'loss'){
this.router.navigate(['arcade-outcome', { type: 'arcade_lose' }]);
} else {
// if (event.data === 'closed') {
let routename = commanSrv.getLastRoute();
navCtrl.navigateBack(routename || 'home_tab');
// }
}
});
}
}
And now
another site is made up of HTML and javascript and here is code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="assets/icon/favicon.png" />
<link rel="stylesheet" type="text/css" href="./assets/css/custom.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.4.3/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.4.3/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.4.3/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.4.3/firebase-database.js"></script>
<script src="scripts/firebase.js"></script>
<script type="text/javascript" src="scripts/index.js"></script>
<title>HTML 5 game application</title>
</head>
<body>
<p>Loader screen</p>
<div class="loader"></div>
<script>
$(document).ready(function(){
const serverUrl = 'https://us-central1-domain.cloudfunctions.net/';
var token;
var xhttp = new XMLHttpRequest();
var gamePlayData;
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const userId = urlParams.get('UID')
const gamePlay = urlParams.get('gameplay')
const mode = urlParams.get('mode')
function getUserDetails(token) {
console.log("getUserDetails start token ", token);
console.log(firebase);
firebase.auth().signInWithCustomToken(token).then((userCredential) => { // execution stop from here.
console.log("getUserDetails end");
var user = userCredential.user;
if (user !== null) {
window.location.replace(`anotherdomain.com/start.html?id=${userId}&gamePlay=${gamePlay}`);
}
})
.catch((error) => {
console.log('error in catch: ', error);
var errorCode = error.code;
var errorMessage = error.message;
// window.history.back();
alert('User is not logged in.')
// parent.postMessage('closed', '*');
});
}
function checkAuth() {
console.log("ajax call start");
$.ajax({
type: "POST",
url: serverUrl + 'checkAuthStatus',
data: { uid: userId },
success: function (response) {
console.log("ajax call end");
//if request if made successfully then the response represent the data
getUserDetails(response.result);
},
error: function (err) {
console.log(err);
}
});
}
checkAuth();
});
</script>
From the line
firebase.auth().signInWithCustomToken(token).then(() => {
Execution cancelled and iframe got closed , window.addEventListener('message', (event) => { got called navigated to ionic application back.
The surprising is, this issue only occurs in iPhone whereas for android it is working fine.
When navigating to another domain site 3rd time then it working and got the success in firebase.auth().signInWithCustomToken(token).then((userCredential) => { .
Please help me.
I installed Hono+Ditto using helm-charts, as it is described in cloud2edge.
That means Hono+Ditto is running inside a minikube on my PC.
I also created a connection, policy, and a device. So far everything works fine.
In the next step, I just wrote a simple "frond-end" to fetch the thing state from Ditto-HTTP-API.
As long as I fetch the thing state manually by the mean of fetch-API everything is fine. But as soon as I try to use the SSE (Eventsource) I get the following CORS error:
index.html:1 Access to resource at 'http://192.168.99.100:32084/api/2/things/de.iot1:dev1' from
origin 'http://localhost:63342' has been blocked by CORS policy: The value of the
'Access-Control-Allow-Origin' header in the response must not be the wildcard '*'
when the request's credentials mode is 'include'.
I am just struggling with this error since yesterday and none of the answers regarding CORS-errors I found on the internet worked :(.
How can I communicate with Ditto from my PC using Eventsource without getting CORs-error?
Below is my simple front-end:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
{
box-sizing: border-box;
}
.container {
display: grid;
}
.row:after {
content: "";
display: table;
clear: both;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<label for="selector">Choose update strategy:
<select name="method" id="selector">
<option value="auto">Autorefresh</option>
<option value="SSE">SSE</option>
</select>
</label>
</div>
<div class="row">
<label for="dev"><h3>Device state:</h3></label>
</div>
<div class="row">
<textarea id="dev" name="dev-data" rows="20" cols="50"></textarea>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
crossorigin="anonymous"></script>
<script>
const baseUrl = "http://192.168.99.100:32084"; // Ditto IP:PORT
const username = "ditto";
const password = "ditto";
const interval = 1000;
const thingId = "de.iot1:dev1";
const thingUrl = `${baseUrl}/api/2/things/${thingId}`;
let intervalId;
let eventSource = null
function requestData(url) {
var headers;
headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', 'Basic ' + btoa(`${username}:${password}`));
init = {
method: 'GET',
headers: headers,
};
var request = new Request(url);
return fetch(request, init)
.then(function (response) {
if (response.ok) {
return response;
}
throw response;
})
}
function updateDeviceState(data) {
$('#dev').val(JSON.stringify(data, null, 2));
}
function onRefresh() {
requestData(thingUrl)
.then(response => {
for (var pair of response.headers.entries()) {
console.log(pair[0] + ': ' + pair[1]);
}
return response.json()
})
.then(data => { updateDeviceState(data) });
}
function enableAutoRefresh(enabled=true) {
if (enabled) {
intervalId = setInterval(() => { onRefresh() }, interval);
} else {
clearInterval(intervalId);
}
}
function enableEventSource(enabled=true) {
if (enabled) {
eventSource = new EventSource(thingUrl, {withCredentials: true})
eventSource.addEventListener('message', (e) => { console.log(e) })
} else if (eventSource != null) {
eventSource.removeEventListener('message', this.eventListener)
eventSource.close();
eventSource = null;
}
}
function applyUpdateStrategy() {
let val = $('#selector').val();
let autoRefreshEnabled = val.includes('auto');
enableAutoRefresh(autoRefreshEnabled);
enableEventSource(!autoRefreshEnabled);
}
$('#selector').on('change', () => { applyUpdateStrategy() })
applyUpdateStrategy()
</script>
</body>
</html>
Thanks!
Thank you for reaching out.
You found a bug which was already fixed the Ditto nginx configuration, however not yet applied to the "packages" project.
I created a PR to fix this, so this should be fixed in the next Helm version of the Ditto chart:
https://github.com/eclipse/packages/pull/193
This question would have been better placed on GitHub as issue - but you could of course not have known that this was a bug before.
I'm having trouble finding a way to do this. I want to display a mat-error on my input form if an http get request fails (status = 404).
I have a search form and every time a user searches for something that doesn't exist I want to display the mat-error telling the user that his search is not valid.
Here's my client side code:
rest.service.ts
private extractData(res: Response) {
let body = res;
return body || { };
}
getOrder(id): Observable<any> {
return this.http.get(endpoint + 'orders/' + id, httpOptions).pipe(
map(this.extractData));
}
getReturns(): Observable<any> {
return this.http.get(endpoint + 'returns', httpOptions).pipe(
map(this.extractData));
}
MyComponent.component.ts
Here I have the getReturnByOrderID function that checks if the response data is empty or not. If it isn't then I open a mat dialog that will lead me to some other part of my site, however, if it is empty then I'm supposed to warn the user that what he has searched for doesn't exist.
I'm also using the getErrorMessage() function to handle all the form errors.
private inputForm = new FormControl('', [Validators.pattern(/^\d+$/)]);
constructor(public rest: RestService, private route: ActivatedRoute, private router: Router, public dialog: MatDialog) { }
getReturnByOrderId(value) {
if (value.length > 0) {
this.rest.getOrder(value).subscribe((data: {}) => {
if (Object.entries(data).length !== 0) {
this.openDialog(data);
} else {
//if 404, do something here
}
});
} else {
this.rest.getReturns().subscribe((data: {}) => {
this.returns = data;
});
}
}
openDialog(el) {
const dialogRef = this.dialog.open(MyDialogComponent, {
width: '70%',
data: el
});
dialogRef.afterClosed().subscribe(result => {
console.log(`Dialog result: ${result}`);
});
}
getErrorMessage() {
return this.inputForm.hasError('pattern') ? 'Insert numeric value!' : '';
// if the get request fails I'd have a message here saying "The order you searched for doesn't exist!"
}
MyComponent.component.html
<div class="row">
<div class="col-2"></div>
<div class="col-8">
<mat-form-field class="search-form-field" appearance="outline">
<mat-label>Search</mat-label>
<input matInput class="search-input" placeholder="Search" [formControl]="inputForm" #searchInput>
<mat-error *ngIf="inputForm?.invalid">{{ getErrorMessage() }}</mat-error>
<mat-hint>Insert an order ID.</mat-hint>
</mat-form-field>
<span matSuffix>
<button mat-raised-button class="search-btn" color="accent" [disabled]="inputForm?.invalid" (click)="getReturnByOrderId(searchInput.value)"><i class="fa fa-search"></i></button>
</span>
</div>
<div class="col-2"></div>
</div>
I'm not sure if my server side code would be usefull, if anyone needs it I'll edit my question...
Any suggestions on how I can achieve this? Thanks for the help!
When the server returns 404 status code, in this case, your subscribe block won't execute. so your need to write error block where you can handle 404 error and set form as invalid like below.
getReturnByOrderId(value) {
if (value.length > 0) {
this.rest.getOrder(value).subscribe((data: {}) => {
if (Object.entries(data).length !== 0) {
this.openDialog(data);
} else {
// if data is empty show
this.inputForm.setErrors({ 'invalid': true });
}
}, error => {
//when 404 error
this.inputForm.setErrors({ 'invalid': true });
});
} else {
this.rest.getReturns().subscribe((data: {}) => {
this.returns = data;
});
}
}
Hope this will help!
This is the java script for paypal payment How to call this from swift 4 and how to pass the amount to this script, now the amount to pay is hard coded
paypal.Button.render({
env: 'sandbox', // sandbox | production
// PayPal Client IDs - replace with your own
// Create a PayPal app: https://developer.paypal.com/developer/applications/create
client: {
sandbox: 'AZDxjDScFpQtjWTOUtWKbyN_bDt4OgqaF4eYXlewfBP4-8aqX3PiV8e1GWU6liB2CUXlkA59kJXE7M6R',
production: '<insert production client id>'
},
// Show the buyer a 'Pay Now' button in the checkout flow
commit: true,
// payment() is called when the button is clicked
payment: function(data, actions) {
// Make a call to the REST api to create the payment
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: '0.01', currency: 'USD' }
}
]
}
});
},
// onAuthorize() is called when the buyer approves the payment
onAuthorize: function(data, actions) {
// Make a call to the REST api to execute the payment
return actions.payment.execute().then(function() {
window.alert('Payment Complete!');
});
}
}, '#paypal-button-container');
The code which I tried is :
#IBAction func buttonActionPay(_ sender: UIButton) {
let htmlPath = Bundle.main.path(forResource: "sampleHTMLCode", ofType: "html")
let url = URL(fileURLWithPath: htmlPath!)
let request = URLRequest(url: url)
webView.load(request)
}
The javascript code above is from paypal developer website and is there any need to edit the code.
Just change the javascript like this.
<!DOCTYPE html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
</head>
<body>
<div id="paypal-button-container"></div>
<script>
// y = 12;
function bar(qq){
var y = qq
paypal.Button.render({
env: 'sandbox', // sandbox | production
// PayPal Client IDs - replace with your own
// Create a PayPal app: https://developer.paypal.com/developer/applications/create
client: {
sandbox: 'AZDxjDScFpQtjWTOUtWKbyN_bDt4OgqaF4eYXlewfBP4-8aqX3PiV8e1GWU6liB2CUXlkA59kJXE7M6R',
production: '<insert production client id>'
},
// Show the buyer a 'Pay Now' button in the checkout flow
commit: true,
// payment() is called when the button is clicked
payment: function(data, actions) {
// Make a call to the REST api to create the payment
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: y, currency: 'USD' }
}
]
}
});
},
// onAuthorize() is called when the buyer approves the payment
onAuthorize: function(data, actions) {
// Make a call to the REST api to execute the payment
return actions.payment.execute().then(function() {
window.alert('Payment Complete!');
});
}
}, '#paypal-button-container');
}
</script>
</body>
The Swift code is:
import UIKit
import WebKit
import JavaScriptCore
class ViewController:
UIViewController,WKUIDelegate,WKNavigationDelegate {
var cont = String()
var jsContext: JSContext!
var webView: WKWebView
required init(coder aDecoder: NSCoder) {
self.webView = WKWebView(frame: CGRect.zero)
super.init(coder: aDecoder)!
}
override func loadView() {
super.loadView()
let userContentController = WKUserContentController()
let source = "bar('12');"
let userScript = WKUserScript(source: source, injectionTime:
WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true)
userContentController.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
self.webView = WKWebView(frame: self.view.frame, configuration:
configuration)
}
override func viewDidLoad() {
super.viewDidLoad()
///
view.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
let height = NSLayoutConstraint(item: webView, attribute: .height,
relatedBy: .equal, toItem: view, attribute: .height, multiplier: 1,
constant: 0)
let width = NSLayoutConstraint(item: webView, attribute: .width,
relatedBy: .equal, toItem: view, attribute: .width, multiplier: 1,
constant: 0)
view.addConstraints([height, width])
let path = Bundle.main.path(forResource: "sampleHTMLCode", ofType:
"html")!
let url = URL(fileURLWithPath: path)
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
///
webView.navigationDelegate = self
}
#IBAction func buttonActionPay(_ sender: UIButton) {
let htmlPath = Bundle.main.path(forResource: "sampleHTMLCode",
ofType: "html")
let url = URL(fileURLWithPath: htmlPath!)
let request = URLRequest(url: url)
webView.load(request)
}
}