I am using nativescript to develop a web radio app and nativescript-audio plugin to read the stream. On Android I have no problem but on iOS the method:
sharedSession.dataTaskWithUrlCompletionHandler(URL, function(data,
response, error)) return with error = {}
Here is part of my Info.plist
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>radioking.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
And here is my url : https://www.radioking.com/play/jobradio
The stream format is mp3
The plugin call :
private player = new TNSPlayer();
public initFromUrl(url : string, autoPlay : boolean = false) {
// Initialize player
this.player.initFromUrl({
audioFile: url,
loop: false,
completeCallback: () => {
this.player.dispose().then(() => { });
},
errorCallback: args => { },
infoCallback: args => { }
}).then(() => {
if (autoPlay) this.player.play();
});
}
Could someone explain me what is wrong ?
Thanks
Finally, I found the solution. As wrote ahead, I replace the AVAudioPlayer by the AVPlayer.
The usefull information in the Info.plist are:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>radioking.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
And in the plugin, I replace all the code in the playFromUrl by:
TNSPlayer.prototype.playFromUrl = function (options) {
var _this = this;
_this._completeCallback = options.completeCallback;
_this._errorCallback = options.errorCallback;
_this._infoCallback = options.infoCallback;
return new Promise(function (resolve, reject) {
if (options.autoPlay !== false) {
options.autoPlay = true;
}
try {
var audioSession = AVAudioSession.sharedInstance();
var output = audioSession.currentRoute.outputs.lastObject.portType;
if (output.match(/Receiver/)) {
try {
audioSession.setCategoryError(AVAudioSessionCategoryPlayAndRecord);
audioSession.overrideOutputAudioPortError(AVAudioSessionPortOverrideSpeaker);
audioSession.setActiveError(true);
common_1.TNS_Player_Log("audioSession category set and active");
}
catch (err) {
common_1.TNS_Player_Log("setting audioSession category failed");
}
}
_this._player = AVPlayer.alloc().initWithURL(NSURL.URLWithString(options.audioFile));
if (_this._player) {
_this._player.delegate = _this;
common_1.TNS_Player_Log("this._player", _this._player);
_this._player.enableRate = true;
_this._player.numberOfLoops = options.loop ? -1 : 0;
if (options.metering) {
common_1.TNS_Player_Log("enabling metering...");
_this._player.meteringEnabled = true;
}
if (options.autoPlay) {
_this._player.play();
}
resolve();
} else {
reject();
}
}
catch (ex) {
if (_this._errorCallback) {
_this._errorCallback({ ex: ex });
}
reject(ex);
}
});
};
With this code, all the controller actions keep working.
online mp3 and web streaming work correctly.
Related
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;
},
I successfully notarized the app and it gives the following error
I checked the signing and notarizing and it gives me the following:
> pkgutil --check-signature ./path/to/app/XXXX.app
Package "XXX":
Status: signed by a certificate trusted by macOS
Certificate Chain:
1. Developer ID Application: ...
and
> spctl -a -t exec -vvv ./path/to/app/XXXX.app
./path/to/app/XXXX.app: accepted
source=Notarized Developer ID
origin=Developer ID Application: XXXXXX (XXXXXX)
electron-notarize version is ^1.0.0
This shows it is successfully notarized, here are my config files (and signing js file if that helps):
package.json
"build": {
"asar": true,
"appId": "redacted",
"files": [
...
],
"afterSign": "./build/afterSignHook.js",
"directories": {
"buildResources": "./build/resources"
},
"publish": [
{
"provider": "github",
"owner": "redacted",
"repo": "redacted"
}
],
"mac": {
"category": "public.app-category.music",
"icon": "assets/appIcons/DJFlame Logo.icns",
"hardenedRuntime": true,
"entitlements": "./build/resources/entitlements.mac.plist",
"asarUnpack": "**/*.node"
},
"dmg": {
"background": null,
"icon": "assets/appIcons/DJFlame Logo.icns",
"backgroundColor": "#202020",
"window": {
...
},
"contents": [
...
]
},
"nsis": {
"oneClick": false,
"perMachine": false,
"installerIcon": "assets/appIcons/DJFlame Logo.ico",
"license": "license.txt"
},
"linux": {
"target": "AppImage",
"icon": "assets/DJFlame Logo.png"
}
}
entitlements.mac.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>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>XXYYZZ112233.com.redacted.redacted</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>
afterSignHook.js (notarizing file)
const fs = require('fs');
const path = require('path');
var electron_notarize = require('electron-notarize');
const config = require('../package.json')
require('dotenv').config();
module.exports = async function (params) {
// Only notarize the app on Mac OS only.
if (process.platform !== 'darwin' || path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`) == '/Users/siddharth/dev/DJTorsten/dist/win-unpacked/DJFlame.app') {
return;
}
// Same appId in electron-builder.
let appId = config.build.appId
let appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
if (!fs.existsSync(appPath)) {
throw new Error(`Cannot find application at: ${appPath}`);
}
const startNoteTime = new Date()
console.log(`Notarizing ${appId} found at ${appPath}. Started Notarizing at ${new Date().toLocaleTimeString()}, expected max finish time ${new Date(new Date().getTime() + 300000).toLocaleTimeString()}`);
try {
await electron_notarize.notarize({
appBundleId: appId,
appPath: appPath,
appleId: process.env.APPLE_ID, // this is your apple ID it should be stored in an .env file
appleIdPassword: process.env.APPLE_ID_PASSWORD, // this is NOT your apple ID password. You need to
//create an application specific password from https://appleid.apple.com under "security" you can generate
//such a password
// ascProvider: process.env.appleIdProvider // this is only needed if you have multiple developer
// profiles linked to your apple ID.
});
} catch (error) {
console.error(error);
throw error;
}
console.log(`Done notarizing ${appId}! Time Finished: ${new Date().toLocaleTimeString()}, Time Elasped: ${Math.floor(new Date() / 1000) - Math.floor(startNoteTime / 1000)}s`);
};
EDIT I narrowed it down to the following lines:
"afterSign": "./build/afterSignHook.js",
"directories": {
"buildResources": "./build/resources"
},
...
"mac": {
...
"hardenedRuntime": true,
"entitlements": "./build/resources/entitlements.mac.plist",
"asarUnpack": "**/*.node"
}
When I'm not getting that error, its also not notarized. I will edit the above snippet until I can find the exact cause of the error.
I tried a bunch of things to fix this, but I think that the following are the answer:
#1 Add a value to package.json
When you add "entitlements": "./build/resources/entitlements.mac.plist", add an inherit that points to the same file. Also add gatekeeperAsses to false. The code would look like
"mac": {
...
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "./build/resources/entitlements.mac.plist",
"entitlementsInherit": "./build/resources/entitlements.mac.plist",
"asarUnpack": "**/*.node"
}
#2 Strip entitlements.mac.plist to bare-minimum
Apparently having too many entitlements may cause this error, so strip it to the entitlements you need. Mine would look like this:
<?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>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>
I'm developing an app and I need to scan iBeacons. I used the beacons_plugin (https://pub.dev/packages/beacons_plugin) and it was working well on Android and iOS. But since the 2.0.0 it's not working anymore on iOS. I tried to understand why but I couldn't. Any help please ?
my 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>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MiLo</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App needs location permissions to scan nearby beacons.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>App needs location permissions to scan nearby beacons.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>App needs location permissions to scan nearby beacons.</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
My widget where I use the plugin :
// All packages needed by the widget
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io' show Platform;
import 'dart:convert';
import 'package:beacons_plugin/beacons_plugin.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_application_1/widgets/beacon_card.dart';
class BeaconDetection extends StatefulWidget {
// Declaration of the variables needed by the widget 1/2
final townId;
final fontsizeValue;
final languageId;
final wordMessageBeforeScan;
final wordButtonLaunchScan;
final wordButtonStopScan;
// Declaration of the variables needed by the widget 2/2
BeaconDetection(
{this.townId,
this.fontsizeValue,
this.languageId,
this.wordMessageBeforeScan,
this.wordButtonLaunchScan,
this.wordButtonStopScan});
#override
_BeaconDetectionState createState() => _BeaconDetectionState();
}
class _BeaconDetectionState extends State<BeaconDetection> {
bool isRunning = false;
String _beaconUuid = '';
double _beaconDistance = 0;
String _beaconDetectedUuid = 'null';
double _beaconDetectedDistance = 0;
final StreamController<String> beaconEventsController =
StreamController<String>.broadcast();
#override
void initState() {
super.initState();
initPlatformState();
}
#override
void dispose() {
beaconEventsController.close();
super.dispose();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
if (Platform.isAndroid) {
// Prominent disclosure
await BeaconsPlugin.setDisclosureDialogMessage(
title: "Need Location Permission",
message: "This app collects location data to work with beacons.");
// Only in case, you want the dialog to be shown again. By Default, dialog will never be shown if permissions are granted.
// await BeaconsPlugin.clearDisclosureDialogShowFlag(false);
}
BeaconsPlugin.listenToBeacons(beaconEventsController);
// Extraction of the name and the uuid of the beacons of the chosen city from the firebase
FirebaseFirestore.instance
.collection('towns/${widget.townId}/beacons')
.snapshots()
.listen((event) {
event.docs.forEach((element) async {
if (element['name'].isNotEmpty == true &&
element['uuid'].isNotEmpty == true &&
element['visibility'] == true) {
await BeaconsPlugin.addRegion(element['name'], element['uuid']);
}
});
});
// When listening the data from beacons detected
beaconEventsController.stream.listen(
(data) {
if (data.isNotEmpty) {
setState(() {
Map _beaconScanned = jsonDecode(data);
_beaconUuid = _beaconScanned['uuid'];
_beaconDistance = double.parse(_beaconScanned['distance']);
});
// print("Beacons DataReceived: " + data);
FirebaseFirestore.instance
.collection('towns/${widget.townId}/beacons')
.where('uuid', isEqualTo: _beaconUuid)
.snapshots()
.listen((event) {
event.docs.forEach((element) {
if (_beaconUuid == element['uuid'] &&
element['visibility'] == true &&
_beaconDistance <= element['distance']) {
print('Beacon: $_beaconUuid | Distance: $_beaconDistance');
_beaconDetectedUuid = _beaconUuid;
_beaconDetectedDistance = _beaconDistance;
}
});
});
}
},
onDone: () {},
onError: (error) {
print("Error: $error");
});
await BeaconsPlugin.runInBackground(
isRunning); // Send 'true' to run in background
if (Platform.isAndroid) {
BeaconsPlugin.channel.setMethodCallHandler((call) async {
if (call.method == 'scannerReady') {
await BeaconsPlugin.startMonitoring();
setState(() {
isRunning = true;
});
}
});
} else if (Platform.isIOS) {
await BeaconsPlugin.startMonitoring();
setState(() {
isRunning = true;
});
}
if (!mounted) return;
}
Widget build(BuildContext context) {
return Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('towns/${widget.townId}/beacons')
.where('uuid', isEqualTo: _beaconDetectedUuid)
.snapshots(),
builder: (ctx, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) // Initialisation state
return Container(
margin: const EdgeInsets.all(10),
height: 314, // Beacon card's size
child: Center(child: CircularProgressIndicator()),
);
if (_beaconDetectedUuid == 'null' &&
isRunning == false) // Before first scan State
return Container(
margin: const EdgeInsets.all(10),
height: 314, // Beacon card's size
child: Center(child: Text(widget.wordMessageBeforeScan)),
);
if (_beaconDetectedUuid == 'null' &&
isRunning == true) // Launch first scan state
return Container(
margin: const EdgeInsets.all(10),
height: 314, // Beacon card's size
child: Center(
child: CircularProgressIndicator(),
),
);
final beacons = snapshot.data!.docs;
return BeaconCard( // When the detection is done => Display the widget 'BeaconCard' with the following data
title: beacons[0]['title'],
monument: beacons[0]['monument'],
image: beacons[0]['image'],
duration: beacons[0]['duration'],
distance: _beaconDetectedDistance,
townId: widget.townId,
uuid: beacons[0]['uuid'],
fontsizeValue: widget.fontsizeValue,
languageId: widget.languageId,
);
}),
isRunning
? FloatingActionButton.extended( // If 'isRunning' is true => Display a button to stop the scan
icon: Icon(Icons.bluetooth_disabled),
label: Text(widget.wordButtonStopScan),
backgroundColor: Colors.red,
onPressed: () async {
await BeaconsPlugin.stopMonitoring();
setState(() {
isRunning = false;
});
},
)
: FloatingActionButton.extended( // If 'isRunning' is false => Display a button to start the scan
icon: Icon(Icons.bluetooth),
label: Text(widget.wordButtonLaunchScan),
backgroundColor: Theme.of(context).primaryColor,
onPressed: () async {
initPlatformState();
await BeaconsPlugin.startMonitoring();
setState(() {
isRunning = true;
_beaconDetectedUuid = 'null';
});
},
),
SizedBox(
height: 16,
)
],
);
}
}
Thanks a lot
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<…>
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">