phonegap plugin barcodescanner not working on iOS - ios

We are developing application for phonegap (2.4.0) - iOS (6) and Android platforms. Our app is using BarcodeScanner plugin.
Plugin is working without any problems on Android, but we have detected some problems on iOS.
At first in the file CDVBarcodeScanner.mm CDVPlugin.h was not found, so we commented if/else check around this line: #import <CORDOVA/CDVPlugin.h> and to config.xml file we have added this line: <plugin name="org.apache.cordova.barcodeScanner" value="CDVBarcodeScanner" />
Then was build successfull without any errors, but after clicking on scan button nothing happened and nothing was written to output.
Then we compared barcodescanner.js for Android and iOS and found that after adding logs at the end of Android js file:
if(!window.plugins) {
console.log("something 1");
window.plugins = {};
}
if (!window.plugins.barcodeScanner) {
window.plugins.barcodeScanner = new BarcodeScanner();
console.log("something 2");
}
output was written after starting of application. In the case of iOS we have also added to similar part some console logs:
(function() {
if (!window.plugins) window.plugins = {}
console.log("something 1");
if (!window.plugins.barcodeScanner) {
window.plugins.barcodeScanner = new BarcodeScanner();
console.log("something 2");
}
else {
console.log("Not installing barcodeScanner: window.plugins.barcodeScanner already exists")
}
})
but no one was written.
Thanks for every advice.

We have tried these changes and plugin works:
we downgraded to phonegap 2.3
we set -O0 compile flags to zxing-all-in-one.cpp
checked all added libraries

Related

Error when asking for Location using expo-location

I've beeing using expo-location since the beginning of my project, and didn't have any problem with this library.
And it is implemented as follow:
import * as Location from 'expo-location';
let { status } = await Location.getForegroundPermissionsAsync();
console.log('STATUS', status);
if (status === 'granted' && !getLocationPermissionStatus) {
setLocationPermissionStatus('granted');
}
But since today, when I've changed my machine and downloaded my project and setup everything again, the project is throwing this error when the notification is called.
Error: Permissions module not found. Are you sure that Expo modules are properly linked? checkPermissions$#http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:460494:32
I'd like some help on this issue.
ps.: I've expo-notifications being called on the same block of code and its not causing any issue.

Library not linking with 0.41 versions of react-native

I'm having issues linking libraries to a react-native project even after attempting to link manually multiple different times. I've gone through a ton of "praised" tutorials with no success.
I'm not an expert in Objective-C/iOS-native, so to isolate the issue I decided to create a HelloWorld Library and a HelloWorld react-native project.
Using:
react-native v0.41.2
react-native-cli v2.0.1
react-native-create-library v1.0.4
xcode v8.2.1
I did the following:
react-native-create-library Lib.
react-native init RNLibTest.
"Successfully linking" (Tried both manually and react-native link ...)
Here is the code:
RNLib
// ./ios/RNLib.h
#import <React/RCTBridgeModule.h>
#interface RNLib : NSObject <RCTBridgeModule>
#end
// ./ios/RNLib.m
#import "RNLib.h"
#implementation RNLib
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(helloWorld:(NSString *)world)
{
return [NSString stringWithFormat:#"hello %#", world];
}
#end
// ./index.js
import { NativeModules } from 'react-native';
const { RNLib } = NativeModules;
console.log(RNLib); // undefined
console.log(NativeModules); // Object: RNLib NOT included
export default RNLib;
HelloWorld / RNLibTest
// index.ios.js
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
import RNLib from 'react-native-lib'; // I installed RNLib with npm and then "linked".
export default class RNLibTest extends Component {
componentDidMount() {
console.log(RNLib); // undefined
}
render() {
return (
<View>
<Text>Hello World</Text>
<Text>{
RNLib.helloWorld("world")
/* throws error "can't read property helloWorld of undefined" */
}</Text>
</View>
);
}
}
AppRegistry.registerComponent('RNLibTest', () => RNLibTest);
My questions:
If the code is not wrong, could it be the xcode project created by react-create-native-library somehow not working with newer versions of react-native?
Is anyone else having these issues? If so, what did you do to fix it?
If you haven't encountered this issue, are you using the latest version of react-native?
What version are you using of xcode, react-native-cli, etc...?
Did anyone have to downgrade to fix this issue?
UPDATE Feb/22/2017
There is a new release of react-native-create-library (v1.1.0) that supports v0.40+. I tried again and updated the code above, but I'm still seeing the same issue.
Here is a link to the GitHub issue. I also uploaded react-native-lib library and LibTest app to GitHub.
Not Sure Whether react-native-create-library support 0.41 RN But from the code i could say you need to import RCT*h files like <React/RCTBridgeModule.h>
Since this is single fine you can create a RNLib.h File in Xcode and check you would get compile time error
Thanks
I don't know what caused the issue but with react-native 0.42 out, I decided to try again.
Same code, same libraries, same everything BUT react-native 0.42, these were my results:
using react-native link => WORKED.
using manual installation => WORKED.
I'm not sure what happened in 0.41 but it is not happening in 0.42!

Writing a Cordova/Ionic Plugin in Swift

I followed the instructions from this site, http://moduscreate.com/writing-a-cordova-plugin-in-swift-for-ios/, for creating my own cordova plugins for iOS platform.
Firstly, I installed plugman and created a new plugin. This is my plugin.xml :
<?xml version='1.0' encoding='utf-8'?>
<plugin id="com-moduscreate-plugins-echoswift" version="0.0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<name>ModusEchoSwift</name>
<js-module name="ModusEchoSwift" src="www/ModusEchoSwift.js">
<clobbers target="modusechoswift" />
</js-module>
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="ModusEchoSwift">
<param name="ios-package" value="ModusEchoSwift" />
</feature>
</config-file>
<source-file src="src/ios/ModusEchoSwift.swift" />
</platform>
</plugin>
Here is my js file for the plugin, i.e. ModusEchoSwift.js:
var exec = require('cordova/exec');
exports.echo = function(arg0, success, error) {
exec(success, error, "ModusEchoSwift", "echo", [arg0]);
};
exports.echojs = function(arg0, success, error) {
if (arg0 && typeof(arg0) === 'string' && arg0.length > 0) {
success(arg0);
} else {
error('Empty message!');
}
};
And this is my native Swift class, i.e. ModusEchoSwift.swift:
#objc(ModusEchoSwift) class ModusEchoSwift : CDVPlugin {
func echo(command: CDVInvokedUrlCommand) {
var pluginResult = CDVPluginResult(
status: CDVCommandStatus_ERROR
)
let msg = command.arguments[0] as? String ?? ""
if msg.characters.count > 0 {
/* UIAlertController is iOS 8 or newer only. */
let toastController: UIAlertController =
UIAlertController(
title: "",
message: msg,
preferredStyle: .Alert
)
self.viewController?.presentViewController(
toastController,
animated: true,
completion: nil
)
let duration = Double(NSEC_PER_SEC) * 3.0
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(duration)
),
dispatch_get_main_queue(),
{
toastController.dismissViewControllerAnimated(
true,
completion: nil
)
}
)
pluginResult = CDVPluginResult(
status: CDVCommandStatus_OK,
messageAsString: msg
)
}
self.commandDelegate!.sendPluginResult(
pluginResult,
callbackId: command.callbackId
)
}
}
These are the files in my plugin. Now I am trying to show a simple alert using this plugin in my ionic project. I have a simple index.html right now,where I wanna display the alert, here it is:
<ion-pane>
<ion-header-bar class="bar-stable">
<h1 class="title">Ionic Blank Starter</h1>
</ion-header-bar>
<ion-content>
<div ng-controller="myController">
Hello {{user}}
</div>
</ion-content>
</ion-pane>
And here is my controller :
.controller('myController', function($scope){
console.log("Ok");
$scope.user = "kAy";
ModusEchoSwift.echo('Plugin Ready!', function(msg) {
console.log("Success");
},
function(err) {
console.log("Error");
}
);
})
Here in this controller, I keep getting the error that ModusEchoSwift is not defined, which I do not understand! Can anyone tell me how to use the function of my plugin in my existing ionic project??
This does work correctly with ionic v2.2.1 & cordova v6.5.0, provided the steps outlined in Simon's blog post are followed, and with one minor change: Add this line of code in the App.component.ts file below the imports:
declare let modusechoswift;
The Bridging-Header.h file in the ionic app was under 'Other Sources' in my case. Simon's post refers to a different location, which initially put me off, but it was a non-issue. In fact, moving around that header file anywhere in my Xcode project did not appear to have any effect. I'm guessing XCode doesn't care where the file is as long as it's present.
I am the author of the blog that you're following, I've checked all of your code that you posted and it all looks correct. It may be that you haven't yet added the bridging header plugin to your Cordova app project that I refer to in my post (quoted below).
In short I think you need to add the plugin referenced below which will help deal with the Objective C to Swift bridging header needed. Also check you have the Modus plugin and the bridging one installed correctly, by doing
cordova plugin ls
In your app project's main folder (the one with config.xml in it). This should return both the ModusEchoSwift and the bridging header plugin in its output if both are correctly installed in the app project.
The Cordova plugin that we have been working on is implemented in
Swift, but the native parts of a Cordova iOS app are written in
Objective-C still. Normally, this isn’t code that we need to be
concerned with, as the Cordova CLI auto generates it for us along with
an Xcode project to compile and build it.
When using Swift to write a plugin however, we do need to modify the
Cordova app’s Xcode project settings to allow our Swift plugin code to
access the Cordova objects that it needs, which are written in
Objective-C. To do this, we make use of a bridging header file.
A bridging header file is an Objective-C header that contains imports
for each Objective-C header that we want to be able to access in our
Swift code. In our case, we need access to some of the Cordova
objects: CDVPlugin, CDVInvokedUrlCommand and CDVPluginResult for
example. This means that our bridging header just needs to contain:
#import <Cordova/CDV.h>
as our plugin won’t be using any other Objective-C references.
CDV.h contains declarations for all of these, and is part of every
Cordova app that the CLI generates.
Our bridging header needs to live in the folder
platforms/ios/ in our Cordova app (e.g. for our TestApp that
we’ll build next this would be platforms/ios/TestApp). It also needs
to be referenced in the Xcode project file so that Xcode knows that
this is a bridging header and that the Objective-C app project also
contains Swift code when compiling and linking the application.
In Cordova, the platforms folder should ideally be a build artifact –
generated entirely by executing Cordova CLI commands. We should not be
editing or adding files manually in this folder. However, we now find
ourselves needing to do so in order to insert the required bridging
header into the Xcode project. Thankfully, Cordova’s CLI supports
hooks that allow us to run scripts before or after certain CLI
commands are executed, precisely to deal with situations such as this.
Hook scripts can be bundled up and distributed with plugins, making
them easy to share and add to projects. GitHub user Alexis Kofman
wrote a handy plugin that installs a hook script to automatically
create the bridging header we need and configure the Xcode project to
use it. His plugin can be found here and we’ll use it when
configuring a test Cordova app to run our Swift plugin with.
For more information on mixing Objective C and Swift in the same
project, we would recommend referring to the Apple documentation
on the subject.
On further investigation it looks like you didn't add the bridging header plugin to your test app BEFORE adding the ios platform or the Swift plugin, this order of events is needed to get the bridging header plugin hook script to fire at the right time.
The following order of commands gets you to a working application from nothing, I just ran this on my local machine to triple check:
cordova create mytest
cd mytest
cordova plugin add cordova-plugin-add-swift-support --save
cordova platform add ios --save
cordova plugin add https://github.com/ModusCreateOrg/cordova-swift-plugin-example
cordova build ios
cordova emulate ios
Let emulator start.
Connect to emulator using Safari remote debugger.
Open JS console
In JS Console:
modusechoswift.echo('hello', undefined);
Observe a native 'toast' with 'hello' message appear from the plugin in the simulator then vanish soon after. Screenshot attached.
call controller 'modusechoswift' not 'ModusEchoSwift' and be sure platform is ready
$ionicPlatform.ready(function() {
modusechoswift.echo('Plugin Ready!', function(msg) {
console.log("Success");
},
function(err) {
console.log("Error");
}
);
});
Usually the "plugin not defined" error means you need to expose the ModusCreate plugin via an Angular service (Ionic is built on AngularJS). Cordova itself doesn't use Angular, which is why that works but Ionic doesn't. There are a couple ways to make the service - I'd look at ngCordova for examples. ngCordova is most likely how cordova-plugin-camera is getting exposed to Angular already.
Once you've done that, you'll need to inject that service into your controller (in much the same way that $scope is already getting injected). After that you should be good to go. Hope that helps.

How can I set the default device to emulate in Ionic?

I'm using Ionic to build an iOS app. Right now I'm testing how it behaves in an iPad 2, but doing this requires me to constantly need to write:
ionic emulate ios --target="iPad-2"
Is there a way to hard-code this somewhere in the ionic.project file or somewhere else so I can stop manually doing this? Thanks
I was going through the same issue and even though this question is a year old but it was the first thing I got through google and couldn't find the answer anywhere else. Here's what I did just because I don't want to use --target="iPhone-7" everytime.
To be clear for anyone who lands here wanting to just run on a specific ios device use the following:
ionic run ios --target="iXXX-X"
The iXXX-X would be one of the names you get from running
ios-sim showdevicetypes
for example:
ionic run ios --target="iPhone-7"
I wanted to have a solution to make iPhone-7 my default, so running the following would target iPhone-7 (My original default target is iPhone-SE):
ionic run ios
It seems like the default is hardcoded and so must be changed in the code.
I found this file: /platforms/ios/cordova/lib/run.js
In there you'll find a function called deployToSim, I changed it as follows:
function deployToSim(appPath, target) {
// Select target device for emulator. Default is 'iPhone-6'
if (!target) {
return require('./list-emulator-images').run()
.then(function(emulators) {
if (emulators.length > 0) {
target = emulators[0];
}
emulators.forEach(function(emulator) {
// this is the original condition
// if (emulator.indexOf('iPhone') === 0)
// change "iPhone" to the specific model you want, in my case it's iPhone-7
// Notice the comma in iPhone7, without comma it will take iPhone-7-plus instead
if (emulator.indexOf('iPhone-7,') === 0) {
target = emulator;
}
});
events.emit('log', 'No target specified for emulator. Deploying to ' + target + ' simulator');
return startSim(appPath, target);
});
} else {
return startSim(appPath, target);
}
}

How do you hide the warnings in React Native iOS simulator?

I just upgraded my React Native and now the iOS simulator has a bunch of warnings. Besides fixing them, how do I hide these warnings so that I can see what's underneath?
According to React Native Documentation, you can hide warning messages by setting disableYellowBox to true like this:
console.disableYellowBox = true;
Update: React Native 0.63+
console.disableYellowBox is removed and now you can use:
import { LogBox } from 'react-native';
LogBox.ignoreLogs(['Warning: ...']); // Ignore log notification by message
LogBox.ignoreAllLogs();//Ignore all log notifications
to ignore all log notifications
A better way to selectively hide certain warnings (that indefinitely show up after an upgrade to the latest and greatest RN version) is to set console.ignoredYellowBox in a common JS file in your project. For example, after upgrading my project today to RN 0.25.1 I was seeing a lot of...
Warning: ReactNative.createElement is deprecated...
I still want to be able to see helpful warnings and error messages from React-Native, but I want to squash this particular warning because it's coming from an external npm library that hasn't yet incorporated the breaking changes in RN 0.25. So in my App.js I add this line...
// RN >= 0.63
import { LogBox } from 'react-native';
LogBox.ignoreLogs(['Warning: ...']);
// RN >= 0.52
import {YellowBox} from 'react-native';
YellowBox.ignoreWarnings(['Warning: ReactNative.createElement']);
// RN < 0.52
console.ignoredYellowBox = ['Warning: ReactNative.createElement'];
This way I still get other errors and warning helpful for my dev environment, but I no longer see that particular one.
To disable the yellow box place
console.disableYellowBox = true;
anywhere in your application. Typically in the root file so it will apply to both iOS and Android.
For example
export default class App extends React.Component {
render() {
console.disableYellowBox = true;
return (<View></View>);
}
}
add this line in your app main screen.
console.disableYellowBox = true;
for example:- in index.js file
import { AppRegistry } from 'react-native';
import './src/utils';
import App from './App';
import { name as appName } from './app.json';
AppRegistry.registerComponent(appName, () => App);
console.disableYellowBox = true;
In your app.js file under any component's lifecycle method.like in componentDidmount()
you have to add both of these,excluding any will not work.
console.ignoredYellowBox = ['Warning: Each', 'Warning: Failed'];
console.disableYellowBox = true;
For me below lines worked currently I am using react native 0.64
import { LogBox } from 'react-native';
LogBox.ignoreLogs(['Warning: ...']); //Hide warnings
LogBox.ignoreAllLogs();//Hide all warning notifications on front-end
When adding your warning to specify exactly which warning to suppress, you need to exactly add the warning message, like so (random example)
LogBox.ignoreLogs([
'Warning: Failed prop type: Invalid props.style key `tintColor` supplied to `Text`.',
]);
Using single quotes instead of backticks around tintColor or Text, for example, will not work.
Add the following code in your index.js file
console.disableYellowBox = true;
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
console.disableYellowBox = true;
AppRegistry.registerComponent(appName, () => App);
If You're Trying to Quickly Demo the App.
If you want to hide them in a particular build because you're doing a demo or something, you can edit your Xcode scheme to make it a release build and these yellow warnings will not show up. Additionally, your app will run much faster.
You can edit the Scheme for your simulator and real device by doing the following:
In Project in XCode.
Product > Scheme > Edit Scheme...
Change Build Configuration from Debug to Release.
For those coming this way trying to disable red warnings from the console, that give absolutely useless information, as of feb/17, you can add this line of code somewhere
console.error = (error) => error.apply;
Disables all console.error
RN >= 0.62
import {LogBox} from 'react-native'
under the import, add
LogBox.ignoreLogs(['...']);
instead of '...',
you can write the warnings you want to hide.
For instance,
I had the warning VirtualizedLists should never be ....
then I can write as
LogBox.ignoreLogs(['VirtualizedLists']);
if you want to add another error, you can write as
LogBox.ignoreLogs(['VirtualizedLists','Warning:...']);
console.disableYellowBox = true;
this worked for application level Put it anywhere in index.js file
I found that even when I disabled specific warnings (yellow-box messages) using the above mentioned methods, the warnings were disabled on my mobile device, but they were still being logged to my console, which was very annoying and distracting.
To prevent warnings from being logged to your console, you can simply override the warn method on the console object.
// This will prevent all warnings from being logged
console.warn = () => {};
It is even possible to disable only specific warnings by testing the provided message:
// Hold a reference to the original function so that it can be called later
const originalWarn = console.warn;
console.warn = (message, ...optionalParams) => {
// Insure that we don't try to perform any string-only operations on
// a non-string type:
if (typeof message === 'string') {
// Check if the message contains the blacklisted substring
if (/Your blacklisted substring goes here/g.test(message))
{
// Don't log the value
return;
}
}
// Otherwise delegate to the original 'console.warn' function
originalWarn(message, ...optionalParams);
};
If you can't (or don't want to) use a Regular Expression to test the string, the indexOf method will work just as well:
// An index of -1 will be returned if the blacklisted substring was NOT found
if (message.indexOf('Your blacklisted substring goes here') > -1) {
// Don't log the message
return;
}
Be aware that this technique will filter all messages that go through the warn function regardless of where they originated from.
Because of this, be careful that you do not specify an overly generous blacklist that will suppress other meaningful errors that may originate from somewhere other than React Native.
Also, I believe that React Native uses the console.error method to log errors (red-box messages), so I'm assuming that this technique could be used to filter out specific errors as well.
Add in app.js
import LogBox from React Native
import {LogBox} from 'react-native';
and then..
LogBox.ignoreAllLogs()
To disable the yellow box place console.disableYellowBox = true; anywhere in your application. Typically in the root file so it will apply to both iOS and Android.
For get more details please check official document
console.disableYellowBox = true;
console.ignoredYellowBox = ['Warning: Each', 'Warning: Failed'];
In your AppDelegate.m file you can change this line :
jsCodeLocation = [NSURL URLWithString:#"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
and replace dev=true by dev=false at the end.
Related: Suppress Xcode warnings from React Native library
(but not for your own code)
why: when initialising a new RN-app, the Xcode project contains closer to 100 warnings that is distracting noise (but probably harmless otherwise)
solution: set inhibit all warnings to yes under Build Settings for the relevant targets.
Disable warnings in Xcode from frameworks
https://github.com/facebook/react-native/issues/11736
I like to put the console.disableYellowBox = true on the file root, like App.
But this just when im on the development phase.
console.error = (error) => error.apply; // in the index.js
Some times rn 0.66 does not works Logbox. especially for VirtualizedLists should never be nested inside plain ScrollViews.
And also ignore red warnings.

Resources