Can't pass headers in flutter_inappwebview & webview_flutter in iOS - ios

versions:
flutter_inappwebview: 5.3.2
webview_flutter: 2.3.1
I'm trying to pass headers to a webview URL, on Android everything is working fine but in ios, I'm getting an unauthorized error displayed.
I tried adding NSAppTransportSecurity in Info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
also enabled embedded preview
<key>io.flutter.embedded_views_preview</key>
<true/>
but unable to make it work. Below is my code.
code:
webview_flutter:
body: WebView(
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (c) {
c.loadUrl(
url,
headers: {'Authorization': 'Bearer ' + token},
);
},
),
flutter_inappwebview:
body: InAppWebView(
initialUrlRequest: URLRequest(
url: Uri.parse(url),
headers: {'Authorization': 'Bearer ' + token},
),
),

initialize variable in the stateful class and try this solution
bool _init = true;
onLoadStop: (controller, url) async {
if (Platform.isIOS) {
if (_isInit) {
await webViewController!.loadUrl(
urlRequest: URLRequest(
url: url,
headers: headers,
),
);
setState(() {
_isInit = false;
});
}
}
pullToRefreshController!.endRefreshing();
this.url = url.toString();
urlController.text = this.url;
},

Related

How to run app on mobile web with flutter URI schemes

I'm trying to start my flutter app when it connects to a specific URI on the mobile web.
Among other methods, we decided to use URI schemes.
Assuming my specific URI link is e.g. https://myFlutterTest.URISchemes
Run the URI like this: https://myFlutterTest.URISchemes/home?<parameter>
I determine whether to run the app normally based on /home. After that, the value of <parameter> is stored in the Map.
I succeeded in receiving android as a URI and running it normally.
But IOS didn't succeed.
Added below to info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>https</string>
</array>
<key>CFBundleURLName</key>
<string>myFlutterTest.URISchemes</string>
</dict>
</array>
main.dart(
The part that receives and determines the URI path)
Widget build(BuildContext context) {
HttpProvider httpProbvider = HttpProvider();
return Platform.isAndroid
? MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: "/",
onGenerateRoute: (RouteSettings path) {
if (path.name!.contains("/home")) {
print("path.name : ${path.name}");
return MaterialPageRoute(
builder: (BuildContext context) => Home(),
);
}
},
)
: CupertinoApp(
debugShowCheckedModeBanner: false,
initialRoute: "/",
onGenerateRoute: (RouteSettings path) {
if (path.name!.contains("/home")) {
print("path.name : ${path.name}");
return CupertinoPageRoute(
builder: (BuildContext context) => Home(),
);
}
},
);
}
}
If you know anything wrong, please let me know. Thank you.

Flutter webview is blank on IOS but working on android

I'm using flutter webview to present the payment url in my app using the following class:
class YourWebView extends StatelessWidget {
String url;
bool isFinshed = false;
YourWebView(this.url);
final Completer<WebViewController> _controller =
Completer<WebViewController>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('اكمال عملية الدفع..'),
leading: new IconButton(
icon: new Icon(Icons.close),
onPressed: () {
if(isFinshed) {
Provider.of<MatchProvider>(context, listen: false)
.getMyComingMatches();
Navigator.of(context).popUntil((route) => route.isFirst);
} else {
Navigator.pop(context);
}
}),
),
body: Builder(builder: (BuildContext context) {
return WebView(
initialUrl: Uri.encodeFull(url),
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
debuggingEnabled: true,
onPageFinished: (String url) {
SystemChannels.textInput.invokeMethod('TextInput.hide');
if (url.contains("tap/check?tap_id")) {
isFinshed = true;
}
print('Page finished loading: $url');
},
gestureRecognizers: null,
// gestureNavigationEnabled: false
);
}));
}
The url looks like:
https://xxxxxx.com/tap/check?tap_id=chg_TS05162021120xxxxxxx
Everything is working on Android, but on IOS i get a blank screen and i see this error in xcode debug logs :
WebPageProxy::didFailProvisionalLoadForFrame
I have tried to run another urls on the webview and it was working, but the payment url isn't, even though it's working on Android or other browsers.
I think you maybe tried to load a http link in webview instead of https. In that case you should add the following in your info.plist file.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
I am not familiar with Flutter, but on iOS, if the system's process for rendering the web content terminated, the webview would be blank, the flutter plugin is handling the situation in here, you may have to check the error and do a reload.

WebView not working in iOS using flutter but working in Android

i am using webview_flutter: 1.0.7 in flutter. It's working in android but not working in iOS.
I have added below code in info.plist for webview_flutter.
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
and webview controller code is
Container(
height: wvHeight,
child: WebView(
onPageFinished: (some) async {
String h = await mWebViewControllerSolution
.evaluateJavascript("document.documentElement.scrollHeight;");
if (h != null) {
print("H = " + h.toString());
double height = double.parse(h);
setState(() {
wvHeight = height;
});
}
},
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
mWebViewControllerSolution = webViewController;
wvSolutionNavigation(context);
},
),
);
wvSolutionNavigation(BuildContext context) async {
String html = getSolution();
if (!Utils.isTable(html)) {
return;
}
if (html.isEmpty) {
return;
}
final String contentBase64 =
base64Encode(const Utf8Encoder().convert(html));
await mWebViewControllerSolution
.loadUrl('data:text/html; charset=utf-8;base64,$contentBase64');
}
giving error :
Unhandled Exception: PlatformException(loadUrl_failed, Failed parsing the URL, Request was: '{
headers = "";
url = "data:text/html; charset=utf-8;base64,PHA+VGhlIGNvcnJlY3QgYW5zd2VyIGlzIDxzdHJvbmc+T3B0aW9uIDI8L3N0cm9uZz4gaS5lJm5ic3A7PHN0cm9uZz5LZXNhdmFuYW5kYSBCaGFyYXRpIGNhc2UuPC9zdHJvbmc+PC9wPg0KDQo8dWw+DQoJPGxpPkluIHRoZSZuYnNwOzxzdHJvbmc+S2VzYXZhbmFuZGEgQmhhcmF0aSBjYXNlPC9zdHJvbmc+LCB0aGUgU3VwcmVtZSBjb3VydCBoZWxkIHRoYXQgdGhlICZxdW90OzxzdHJvbmc+YmFzaWMgc3RydWN0dXJlIG9mIHRoZSBDb25zdGl0dXRpb24gY291bGQgbm90IGJlIGFicm9nYXRlZCBldmVuIGJ5IGEgY29uc3RpdHV0aW9uYWwgYW1lbmRtZW50JnF1b3Q7PC9zdHJvbmc+PC9saT4NCjwvdWw+DQoNCjx0YWJsZSBib3JkZXI9IjEiIGNlbGxwYWRkaW5nPSIxIiBjZWxsc3BhY2luZz0iMSIgc3R5bGU9IndpZHRoOjM4OC4wcHgiPg0KCTx0Ym9keT4NCgkJPHRyPg0KCQkJPHRkIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+PHN0cm9uZz5DYXNlczwvc3Ryb25nPjwvdGQ+DQoJCQk8dGQgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj48c3Ryb25nPlN1cHJlbWUgQ291cnQgdmVyZGljdDwvc3Ryb25nPjwvdGQ+DQoJCTwvdHI+DQoJCTx0cj4NCgkJCTx0ZD5Hb2xha25hdG<…>

Flutter Webview Apple Pay

In an attempt to use WebViewController.evaluateJavascript('myjs') I get this error in my debug console.
[VERBOSE-2:ui_dart_state.cc(166)] Unhandled Exception: PlatformException(evaluateJavaScript_failed, Failed evaluating JavaScript, JavaScript string was: 'doucment.getElementById("checkout_email").value = "Hell0";'
Error Domain=WKErrorDomain Code=4 "A JavaScript exception occurred" UserInfo={WKJavaScriptExceptionLineNumber=0, WKJavaScriptExceptionMessage=Unable to run user agent scripts because this document has previously accessed Apple Pay. Documents can be prevented from accessing Apple Pay by adding a WKUserScript to the WKWebView's WKUserContentController., WKJavaScriptExceptionColumnNumber=0, NSLocalizedDescription=A JavaScript exception occurred})
#0 StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:572
#1 MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:161
<asynchronous suspension>
#2 MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:334
#3 MethodChannelWebViewPlatform<…>
My Dart file looks like this,
On page load I do a simple check to ensure I execute the js on the correct page. If the check passes the js is executed but unfortunately returns the error above. Ive tried looking all over Google for an answer but ive found nothing similar to the issue I am having.
final Completer<WebViewController> _controller =
Completer<WebViewController>();
TextEditingController _searchQueryController = TextEditingController();
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
elevation: 0,
title: _searchBar(),
leading: _directionButton('backward'),
actions: [_directionButton('forward')],
),
body: WebView(
initialUrl: 'https://google.com',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
onPageStarted: (url) {
_searchQueryController.text = url;
},
onPageFinished: (url) async {
print('Page Finished: ' + url);
final controller = await _controller.future;
if (url.contains('checkouts')) {
await controller.evaluateJavascript('doucment.getElementById("checkout_email").value = "Hello";');
}
},
),
));
}
Try to add this into your info.plist , Replasing domain of your payment gateway
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>yourdomain.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
and Dont forget to re-install app

Ionic 3: WARNING: sanitizing unsafe URL value

I´m trying to take a photo and analyze it with the tesseract OCR engine in ionic 3 App for iOS. I´m trying to run it on a iPhone 8 iOS 11.2.6
Unfortunately I get an error in Xcode after taking a photo, and the app crashes:
NSURLConnection finished with error - code -1002
and also WARNING: sanitizing unsafe URL value assets-library://asset/asset.JPG?id=A791150A-3E89-400E-99D3-E7B3A3D888AA&ext=JPG
Thank you for your help
home.html
<h3 *ngIf="debugText">Debug: {{debugText}}</h3>
<span>{{recognizedText}}</span>
<!--<img src="assets/img/demo.png" #demoImg class="start-api" />-->
<img [src]="image" #imageResult />
<div *ngIf="_ocrIsLoaded && !image">
<!--<img src="assets/img/Start-arrow.png" #start class="start-arrow" />-->
</div>
home.ts:
import { Component, ViewChild, ElementRef, NgZone } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Camera } from '#ionic-native/camera';
import { Platform, ActionSheetController, LoadingController } from 'ionic-angular';
import Tesseract from 'tesseract.js';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
#ViewChild('imageResult') private imageResult: ElementRef;
#ViewChild('demoImg') private demoImg: ElementRef;
private recognizedText: string;
image: string = '';
_zone: any;
_ocrIsLoaded: boolean = false;
brightness: number = 12;
contrast: number = 52;
unsharpMask: any = { radius: 100, strength: 2 };
hue: number = -100;
saturation: number = -100;
showEditFilters: boolean = false;
debugText: string = '';
constructor(
private camera: Camera,
public navCtrl: NavController,
public platform: Platform,
public loadingCtrl: LoadingController,
public actionsheetCtrl: ActionSheetController) {
this._zone = new NgZone({ enableLongStackTrace: false });
}
openMenu() {
if (this._ocrIsLoaded === true) {
let actionSheet;
if (!this.image) {
actionSheet = this.actionsheetCtrl.create({
title: 'Actions',
cssClass: 'action-sheets-basic-page',
buttons: [
{
text: 'Random demo',
icon: !this.platform.is('ios') ? 'shuffle' : null,
handler: () => {
this.randomDemo()
}
},
{
text: 'Take Photo',
icon: !this.platform.is('ios') ? 'camera' : null,
handler: () => {
this.takePicture()
}
},
{
text: 'Cancel',
role: 'cancel', // will always sort to be on the bottom
icon: !this.platform.is('ios') ? 'close' : null,
handler: () => {
console.log('Cancel clicked');
}
}
]
});
}
else {
actionSheet = this.actionsheetCtrl.create({
title: 'Actions',
cssClass: 'action-sheets-basic-page',
buttons: [
{
text: 'Random demo',
icon: !this.platform.is('ios') ? 'shuffle' : null,
handler: () => {
this.randomDemo()
}
},
{
text: 'Re-Take photo',
icon: !this.platform.is('ios') ? 'camera' : null,
handler: () => {
this.takePicture()
}
},
{
text: 'Apply filters',
icon: !this.platform.is('ios') ? 'barcode' : null,
handler: () => {
this.filter()
}
},
{
text: 'Clean filters',
icon: !this.platform.is('ios') ? 'refresh' : null,
handler: () => {
this.restoreImage()
}
},
{
text: this.showEditFilters == false ? 'Customize filters' : 'Hide customization filters',
icon: !this.platform.is('ios') ? 'hammer' : null,
handler: () => {
this.showEditFilters = this.showEditFilters == false ? true : false;
}
},
{
text: 'Read image',
icon: !this.platform.is('ios') ? 'analytics' : null,
handler: () => {
this.analyze(this.imageResult.nativeElement.src, false);
}
},
{
text: 'Cancel',
role: 'cancel', // will always sort to be on the bottom
icon: !this.platform.is('ios') ? 'close' : null,
handler: () => {
console.log('Cancel clicked');
}
}
]
});
}
actionSheet.present();
}
else {
alert('OCR API is not loaded');
}
}
restoreImage() {
if (this.image) {
this.imageResult.nativeElement.src = this.image;
}
}
takePicture() {
let loader = this.loadingCtrl.create({
content: 'Please wait...'
});
loader.present();
// Take a picture saving in device, as jpg and allows edit
this.camera.getPicture({
quality: 100,
destinationType: this.camera.DestinationType.NATIVE_URI,
encodingType: this.camera.EncodingType.JPEG,
targetHeight: 1000,
sourceType: 1,
allowEdit: true,
saveToPhotoAlbum: true,
correctOrientation: true
}).then((imageURI) => {
loader.dismissAll();
this.image = imageURI;
this.debugText = imageURI;
}, (err) => {
//console.log(`ERROR -> ${JSON.stringify(err)}`);
});
}
filter() {
/// Initialization of glfx.js
/// is important, to use js memory elements
/// access to Window element through (<any>window)
try {
var canvas = (<any>window).fx.canvas();
} catch (e) {
alert(e);
return;
}
/// taken from glfx documentation
var imageElem = this.imageResult.nativeElement; // another trick is acces to DOM element
var texture = canvas.texture(imageElem);
canvas.draw(texture)
.hueSaturation(this.hue / 100, this.saturation / 100)//grayscale
.unsharpMask(this.unsharpMask.radius, this.unsharpMask.strength)
.brightnessContrast(this.brightness / 100, this.contrast / 100)
.update();
/// replace image src
imageElem.src = canvas.toDataURL('image/png');
}
analyze(image, loadAPI) {
let loader = this.loadingCtrl.create({
content: 'Please wait...'
});
loader.present();
if (loadAPI == true) {
this._ocrIsLoaded = false;
}
/// Recognize data from image
Tesseract.recognize(image, {})
.progress((progress) => {
this._zone.run(() => {
loader.setContent(`${progress.status}: ${Math.floor(progress.progress * 100)}%`)
console.log('progress:', progress);
})
})
.then((tesseractResult) => {
this._zone.run(() => {
loader.dismissAll();
if (loadAPI == true) {
this._ocrIsLoaded = true;
}
console.log('Tesseract result: ');
console.log(tesseractResult);
/// Show a result if data isn't initializtion
if (loadAPI != true) { this.recognizedText = tesseractResult.text; }
});
});
}
randomDemo() {
}
ionViewDidLoad() {
console.log('loaded')
this.analyze(this.demoImg.nativeElement.src, true);
}
}
info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>Diagnyzer</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIcons</key>
<dict/>
<key>CFBundleIcons~ipad</key>
<dict/>
<key>CFBundleIdentifier</key>
<string>io.ionic.diagnyzer</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.0.1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSMainNibFile</key>
<string/>
<key>NSMainNibFile~ipad</key>
<string/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIRequiresFullScreen</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>ionic.local</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs read/write-access photo library access</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string/>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs write-access to photo library</string>
</dict>
</plist>
I do not know much about Ionic, but loading an img in Angular could cause an UnsafeUrl Exception.
Maybe you need to use a Dom Sanitizer.
DomSanitizer using example:
Inject it:
constructor(private sanitizer: DomSanitizer,) {}
And use a function to get the img content:
getImgContent(): SafeUrl {
return this.sanitizer.bypassSecurityTrustUrl(this.imgFile);
}
So you use in HTML Part:
<img class="object-img"
[src]="getImgContent()">
Answering a bit late, but try to add File Path plugin to your project. You can pass your URL and the plugin will resolve it.
Note that this plugin is supported only on Android devices
only put en el get Response ( as string) example
TS
let routeImg = (data.base as string);
HTML
<img *ngIf="routeImg " src="routeImg">

Resources