I added admob interstitial to my android app.
The app and interstitial are working fine on emulator, with TestID and a real ID. But on real devices it is not showing any ad, and there is no crashes or errors.
Could you please help me to find what might be the reason? Here is my code :
import admob, { InterstitialAd, TestIds, AdEventType } from '#react-native-firebase/admob';
...
showAdss(){
const idx = 'ca-app-pub-3....10';
const interstitial = InterstitialAd.createForAdRequest(idx, {
requestNonPersonalizedAdsOnly: true,
keywords: ['fashion', 'clothing']
});
interstitial.onAdEvent((type) => {
if (type === AdEventType.LOADED) {
interstitial.show();
}
});
and from manifest file :
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
...
I'm building an app in android webview while loading html content from an external web server. The html content contains javascript code that uses geolocation to get user current position. The codes works fine in Chrome and Firefox but provides an error in android webview app. What should I do?
I'm targeting android with API 20 or higher and I have tried to include extra permission in android manifest file but nothing worked.
Here HTML code file with Javascript code in an external server:
//get location
//var a = document.getElementById("demo");
var b = document.getElementById("lat");
var c = document.getElementById("long");
var d = document.getElementById("showDiv");
var apiGeolocationSuccess = function(position) {
b.style.display="block";
c.style.display="block";
b.value = position.coords.latitude;
c.value = position.coords.longitude;
alert("API geolocation success!\n\nlat = " + position.coords.latitude + "\nlng = " + position.coords.longitude);
};
var tryAPIGeolocation = function() {
jQuery.post( "https://www.googleapis.com/geolocation/v1/geolocate?key=AIzaSyDCa1LUe1vOczX1hO_iGYgyo8p_jYuGOPU", function(success) {
apiGeolocationSuccess({coords: {latitude: success.location.lat, longitude: success.location.lng}});
})
.fail(function(err) {
alert("API Geolocation error! \n\n"+err);
});
};
var browserGeolocationSuccess = function(position) {
b.value = position.coords.latitude;
c.value = position.coords.longitude;
d.style.display = "block";
alert("Browser geolocation success!\n\nlat = " + position.coords.latitude + "\nlng = " + position.coords.longitude);
};
var browserGeolocationFail = function(error) {
switch (error.code) {
case error.TIMEOUT:
alert("Browser geolocation error !\n\nTimeout.");
break;
case error.PERMISSION_DENIED:
if(error.message.indexOf("Only secure origins are allowed") == 0) {
tryAPIGeolocation();
}
break;
case error.POSITION_UNAVAILABLE:
alert("Browser geolocation error !\n\nPosition unavailable.");
break;
}
};
var tryGeolocation = function() {
b.style.display="block";
c.style.display="block";
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
browserGeolocationSuccess,
browserGeolocationFail,
{maximumAge: 50000, timeout: 20000, enableHighAccuracy: true});
}
};
tryGeolocation();
Android Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.erosaapp">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_GPS" />
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.java.
/*** ------- */
package com.example.erosaapp;
import android.annotation.SuppressLint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
/*
WebViewClient subclass loads all hyperlinks in the existing WebView
*/
public class GeoWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// When user clicks a hyperlink, load in the existing WebView
view.loadUrl(url);
return true;
}
}
/**
* WebChromeClient subclass handles UI-related calls
* Note: think chrome as in decoration, not the Chrome browser
*/
public class GeoWebChromeClient extends WebChromeClient {
#Override
public void onGeolocationPermissionsShowPrompt(String origin,
GeolocationPermissions.Callback callback) {
// Always grant permission since the app itself requires location
// permission and the user has therefore already granted it
callback.invoke(origin, true, false);
}
}
WebView myWebView;
#SuppressLint("SetJavaScriptEnabled")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String myurl = "https://erosa2019.000webhostapp.com";
myWebView = (WebView)findViewById(R.id.webView);
WebSettings webSettings = myWebView.getSettings();
// Brower niceties -- pinch / zoom, follow links in place
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setBuiltInZoomControls(false);
webSettings.setDefaultZoom(WebSettings.ZoomDensity.FAR);
webSettings.setSupportZoom(false);
webSettings.setDefaultFontSize(20);
myWebView.setWebViewClient(new GeoWebViewClient());
// Below required for geolocation
webSettings.setJavaScriptEnabled(true);
webSettings.setGeolocationEnabled(true);
webSettings.setAppCacheEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setGeolocationDatabasePath(getFilesDir().getPath());
myWebView.setWebChromeClient(new GeoWebChromeClient());
myWebView.loadUrl(myurl);
}
#Override
public void onBackPressed() {
if(myWebView.canGoBack()) {
myWebView.goBack();
} else {
super.onBackPressed();
}
}
}
I expect to get prompt asking for permission to have latitude and longtude, but gives "Browser geolocation error! position unavailable"
I've been doing some research and android seems a bit stricter on waking up screen (light up device screen) when push notification is received.
What I would like to achieve is like a text message notification that it would turn on the screen, sound and vibrate. But my push notification only chime or vibrate. Is waking up the device from sleeping possible in cordova? I am using pubnub for the backend.
Here's my sample fcm payload:
var pushPayload = {
"message": "Some message",
"user_id": "1",
"pn_gcm" : {
"priority" : "high",
"data" : {
"title":"Notification title",
"body":"You are a winner!",
"room" : "Room name",
//"count" : 5,
"content-available":"1",
"force-start": "1",
"priority":2
}
}
};
And here's my piece of AndroidManifest.xml
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="27" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
I am using phonegap-plugin-push.
Ok, I ended up creating my own cordova plugin just to handle on waking up screen. And here's the code that I used in my plugin:
Context context = this.cordova.getActivity().getApplicationContext();
PowerManager powerManager = (PowerManager) context.getSystemService(context.POWER_SERVICE);
boolean result= Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT_WATCH&&powerManager.isInteractive()|| Build.VERSION.SDK_INT< Build.VERSION_CODES.KITKAT_WATCH&&powerManager.isScreenOn();
if (!result){
PowerManager.WakeLock wl = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK |PowerManager.ACQUIRE_CAUSES_WAKEUP |PowerManager.ON_AFTER_RELEASE,"MH24_SCREENLOCK");
wl.acquire(10000);
PowerManager.WakeLock wl_cpu = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MH24_SCREENLOCK");
wl_cpu.acquire(10000);
}`
So, in the notification event, I called my plugin like this:
`
push.on('notification', function(data) {
//call wakeup screen
window.plugins.wakeUpScreen.wakeup(function() {
console.log('Wake up!');
}, function(err) {
console.log('Wake up error: ' + err);
});
}); `
Android devices have their own notification preferences and some cannot be overridden by your app. The "Ambient Display" setting will have the screen wake upon notification, but this is a feature that must be turned on in the phone settings.
Can anyone tell me what's wrong with my code error and I couldn't solve it and I wondered can you guys tell me what is wrong with my code.
This is my MapsActivity.java
package com.ite.googlemap;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapsActivity extends FragmentActivity {
GoogleMap Map;
private static final LatLng ITE_COLLEGE_WEST = new LatLng(1.374935, 103.751998);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
try{
if(Map==null) {
Map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
Map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
Map.addMarker(new MarkerOptions().position(ITE_COLLEGE_WEST).title("ITE COLLEGE WEST"));
Map.moveCamera(CameraUpdateFactory.newLatLngZoom(ITE_COLLEGE_WEST, 0));
Map.animateCamera(CameraUpdateFactory.zoomTo(15), 2000, null);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
This is my activity_maps.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ite.googlemap.MapsActivity"
class="com.google.android.gms.maps.MapFragment"
/>
This is what happen after I run the app when Messages Gradle Build Pop up
Information:Gradle tasks [:app:clean, :app:generateDebugSources, :app:generateDebugAndroidTestSources, :app:mockableAndroidJar, :app:prepareDebugUnitTestDependencies, :app:assembleDebug]
:app:clean
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:checkDebugManifest
:app:preReleaseBuild UP-TO-DATE
:app:prepareComAndroidSupportAnimatedVectorDrawable2400Library
:app:prepareComAndroidSupportAppcompatV72400Library
:app:prepareComAndroidSupportMediarouterV72400Library
:app:prepareComAndroidSupportPaletteV72400Library
:app:prepareComAndroidSupportSupportV42400Library
:app:prepareComAndroidSupportSupportVectorDrawable2400Library
:app:prepareComGoogleAndroidGmsPlayServices1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAds1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAdsLite1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAnalytics1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAnalyticsImpl1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAppinvite1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAuth1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAuthBase1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAwareness1001Library
:app:prepareComGoogleAndroidGmsPlayServicesBase1001Library
:app:prepareComGoogleAndroidGmsPlayServicesBasement1001Library
:app:prepareComGoogleAndroidGmsPlayServicesCast1001Library
:app:prepareComGoogleAndroidGmsPlayServicesCastFramework1001Library
:app:prepareComGoogleAndroidGmsPlayServicesClearcut1001Library
:app:prepareComGoogleAndroidGmsPlayServicesDrive1001Library
:app:prepareComGoogleAndroidGmsPlayServicesFitness1001Library
:app:prepareComGoogleAndroidGmsPlayServicesGames1001Library
:app:prepareComGoogleAndroidGmsPlayServicesGass1001Library
:app:prepareComGoogleAndroidGmsPlayServicesGcm1001Library
:app:prepareComGoogleAndroidGmsPlayServicesIdentity1001Library
:app:prepareComGoogleAndroidGmsPlayServicesIid1001Library
:app:prepareComGoogleAndroidGmsPlayServicesInstantapps1001Library
:app:prepareComGoogleAndroidGmsPlayServicesLocation1001Library
:app:prepareComGoogleAndroidGmsPlayServicesMaps1001Library
:app:prepareComGoogleAndroidGmsPlayServicesNearby1001Library
:app:prepareComGoogleAndroidGmsPlayServicesPanorama1001Library
:app:prepareComGoogleAndroidGmsPlayServicesPlaces1001Library
:app:prepareComGoogleAndroidGmsPlayServicesPlus1001Library
:app:prepareComGoogleAndroidGmsPlayServicesSafetynet1001Library
:app:prepareComGoogleAndroidGmsPlayServicesTagmanager1001Library
:app:prepareComGoogleAndroidGmsPlayServicesTagmanagerApi1001Library
:app:prepareComGoogleAndroidGmsPlayServicesTagmanagerV4Impl1001Library
:app:prepareComGoogleAndroidGmsPlayServicesTasks1001Library
:app:prepareComGoogleAndroidGmsPlayServicesVision1001Library
:app:prepareComGoogleAndroidGmsPlayServicesWallet1001Library
:app:prepareComGoogleAndroidGmsPlayServicesWearable1001Library
:app:prepareComGoogleFirebaseFirebaseAnalytics1001Library
:app:prepareComGoogleFirebaseFirebaseAnalyticsImpl1001Library
:app:prepareComGoogleFirebaseFirebaseAppindexing1001Library
:app:prepareComGoogleFirebaseFirebaseAuth1001Library
:app:prepareComGoogleFirebaseFirebaseCommon1001Library
:app:prepareComGoogleFirebaseFirebaseConfig1001Library
:app:prepareComGoogleFirebaseFirebaseCrash1001Library
:app:prepareComGoogleFirebaseFirebaseDatabase1001Library
:app:prepareComGoogleFirebaseFirebaseDatabaseConnection1001Library
:app:prepareComGoogleFirebaseFirebaseIid1001Library
:app:prepareComGoogleFirebaseFirebaseMessaging1001Library
:app:prepareComGoogleFirebaseFirebaseStorage1001Library
:app:prepareComGoogleFirebaseFirebaseStorageCommon1001Library
:app:prepareDebugDependencies
:app:compileDebugAidl
:app:compileDebugRenderscript
:app:generateDebugBuildConfig
:app:mergeDebugShaders
:app:compileDebugShaders
:app:generateDebugAssets
:app:mergeDebugAssets
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources
:app:mergeDebugResources
:app:processDebugManifest
D:\GoogleMap\app\src\main\AndroidManifest.xml:33:5-35:23 Warning:
Element uses-permission#android.permission.ACCESS_FINE_LOCATION at AndroidManifest.xml:33:5-35:23 duplicated with element declared at AndroidManifest.xml:10:5-79
:app:processDebugResources
:app:generateDebugSources
:app:preDebugAndroidTestBuild UP-TO-DATE
:app:prepareDebugAndroidTestDependencies
:app:compileDebugAndroidTestAidl
:app:processDebugAndroidTestManifest
:app:compileDebugAndroidTestRenderscript
:app:generateDebugAndroidTestBuildConfig
:app:mergeDebugAndroidTestShaders
:app:compileDebugAndroidTestShaders
:app:generateDebugAndroidTestAssets
:app:mergeDebugAndroidTestAssets
:app:generateDebugAndroidTestResValues UP-TO-DATE
:app:generateDebugAndroidTestResources
:app:mergeDebugAndroidTestResources
:app:processDebugAndroidTestResources
:app:generateDebugAndroidTestSources
:app:mockableAndroidJar UP-TO-DATE
:app:preDebugUnitTestBuild UP-TO-DATE
:app:prepareDebugUnitTestDependencies
:app:incrementalDebugJavaCompilationSafeguard
:app:compileDebugJavaWithJavac
:app:compileDebugJavaWithJavac - is not incremental (e.g. outputs have changed, no previous execution, etc.).
D:\GoogleMap\app\src\main\java\com\ite\googlemap\MapsActivity.java
Error:(23, 86) error: cannot find symbol method getMap()
:app:compileDebugJavaWithJavac FAILED
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
Compilation failed; see the compiler error output for details.
Information:BUILD FAILED
Information:Total time: 12.34 secs
Information:2 errors
Information:0 warnings
Information:See complete output in console
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ite.googlemap">
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true">
</uses-feature>
<uses-permission
android:name="android.permission.INTERNET">
</uses-permission>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE">
</uses-permission>
<uses-permission
android:name="com.google.android.providers.gsf.permission.READ_GSERVICES">
</uses-permission>
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION">
</uses-permission>
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION">
</uses-permission>
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE">
</uses-permission>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyD-k_r65Lu-yME0H2uW3gjNqGdgHoub4e4" />
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version">
</meta-data>
<activity
android:name=".MapsActivity"
android:label="#string/title_activity_maps">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Information:Gradle tasks [:app:clean, :app:generateDebugSources, :app:generateDebugAndroidTestSources, :app:mockableAndroidJar, :app:prepareDebugUnitTestDependencies, :app:assembleDebug]
:app:clean
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:checkDebugManifest
:app:preReleaseBuild UP-TO-DATE
:app:prepareComAndroidSupportAnimatedVectorDrawable2400Library
:app:prepareComAndroidSupportAppcompatV72400Library
:app:prepareComAndroidSupportMediarouterV72400Library
:app:prepareComAndroidSupportPaletteV72400Library
:app:prepareComAndroidSupportSupportV42400Library
:app:prepareComAndroidSupportSupportVectorDrawable2400Library
:app:prepareComGoogleAndroidGmsPlayServices1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAds1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAdsLite1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAnalytics1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAnalyticsImpl1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAppinvite1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAuth1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAuthBase1001Library
:app:prepareComGoogleAndroidGmsPlayServicesAwareness1001Library
:app:prepareComGoogleAndroidGmsPlayServicesBase1001Library
:app:prepareComGoogleAndroidGmsPlayServicesBasement1001Library
:app:prepareComGoogleAndroidGmsPlayServicesCast1001Library
:app:prepareComGoogleAndroidGmsPlayServicesCastFramework1001Library
:app:prepareComGoogleAndroidGmsPlayServicesClearcut1001Library
:app:prepareComGoogleAndroidGmsPlayServicesDrive1001Library
:app:prepareComGoogleAndroidGmsPlayServicesFitness1001Library
:app:prepareComGoogleAndroidGmsPlayServicesGames1001Library
:app:prepareComGoogleAndroidGmsPlayServicesGass1001Library
:app:prepareComGoogleAndroidGmsPlayServicesGcm1001Library
:app:prepareComGoogleAndroidGmsPlayServicesIdentity1001Library
:app:prepareComGoogleAndroidGmsPlayServicesIid1001Library
:app:prepareComGoogleAndroidGmsPlayServicesInstantapps1001Library
:app:prepareComGoogleAndroidGmsPlayServicesLocation1001Library
:app:prepareComGoogleAndroidGmsPlayServicesMaps1001Library
:app:prepareComGoogleAndroidGmsPlayServicesNearby1001Library
:app:prepareComGoogleAndroidGmsPlayServicesPanorama1001Library
:app:prepareComGoogleAndroidGmsPlayServicesPlaces1001Library
:app:prepareComGoogleAndroidGmsPlayServicesPlus1001Library
:app:prepareComGoogleAndroidGmsPlayServicesSafetynet1001Library
:app:prepareComGoogleAndroidGmsPlayServicesTagmanager1001Library
:app:prepareComGoogleAndroidGmsPlayServicesTagmanagerApi1001Library
:app:prepareComGoogleAndroidGmsPlayServicesTagmanagerV4Impl1001Library
:app:prepareComGoogleAndroidGmsPlayServicesTasks1001Library
:app:prepareComGoogleAndroidGmsPlayServicesVision1001Library
:app:prepareComGoogleAndroidGmsPlayServicesWallet1001Library
:app:prepareComGoogleAndroidGmsPlayServicesWearable1001Library
:app:prepareComGoogleFirebaseFirebaseAnalytics1001Library
:app:prepareComGoogleFirebaseFirebaseAnalyticsImpl1001Library
:app:prepareComGoogleFirebaseFirebaseAppindexing1001Library
:app:prepareComGoogleFirebaseFirebaseAuth1001Library
:app:prepareComGoogleFirebaseFirebaseCommon1001Library
:app:prepareComGoogleFirebaseFirebaseConfig1001Library
:app:prepareComGoogleFirebaseFirebaseCrash1001Library
:app:prepareComGoogleFirebaseFirebaseDatabase1001Library
:app:prepareComGoogleFirebaseFirebaseDatabaseConnection1001Library
:app:prepareComGoogleFirebaseFirebaseIid1001Library
:app:prepareComGoogleFirebaseFirebaseMessaging1001Library
:app:prepareComGoogleFirebaseFirebaseStorage1001Library
:app:prepareComGoogleFirebaseFirebaseStorageCommon1001Library
:app:prepareDebugDependencies
:app:compileDebugAidl
:app:compileDebugRenderscript
:app:generateDebugBuildConfig
:app:mergeDebugShaders
:app:compileDebugShaders
:app:generateDebugAssets
:app:mergeDebugAssets
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources
:app:mergeDebugResources
:app:processDebugManifest
:app:processDebugResources
:app:generateDebugSources
:app:preDebugAndroidTestBuild UP-TO-DATE
:app:prepareDebugAndroidTestDependencies
:app:compileDebugAndroidTestAidl
:app:processDebugAndroidTestManifest
:app:compileDebugAndroidTestRenderscript
:app:generateDebugAndroidTestBuildConfig
:app:mergeDebugAndroidTestShaders
:app:compileDebugAndroidTestShaders
:app:generateDebugAndroidTestAssets
:app:mergeDebugAndroidTestAssets
:app:generateDebugAndroidTestResValues UP-TO-DATE
:app:generateDebugAndroidTestResources
:app:mergeDebugAndroidTestResources
:app:processDebugAndroidTestResources
:app:generateDebugAndroidTestSources
:app:mockableAndroidJar UP-TO-DATE
:app:preDebugUnitTestBuild UP-TO-DATE
:app:prepareDebugUnitTestDependencies
:app:incrementalDebugJavaCompilationSafeguard
:app:compileDebugJavaWithJavac
:app:compileDebugJavaWithJavac - is not incremental (e.g. outputs have changed, no previous execution, etc.).
F:\Mobile Apps\Lab 15\GoogleMap\app\src\main\java\com\ite\googlemap\MapsActivity.java
Error:(23, 86) error: cannot find symbol method getMap()
:app:compileDebugJavaWithJavac FAILED
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
Compilation failed; see the compiler error output for details.
Information:BUILD FAILED
Information:Total time: 2 mins 39.708 secs
Information:2 errors
Information:0 warnings
Information:See complete output in console
Many of us would have gone through similar issues, but even after going through following most relevant links reference link1 and reference link2 , I am not able to resolve.
Issue:
Create a custom plugin (Cordova) in-order to use this in ionic2
project.
Expectation: This plugin will be able to interact with native features of IOS and Android. To be precise I am trying to access features of a native SDK (Aruba Internal Positioning SDK) using cordova into Ionic project.
Step 1 Initially created plugin as per reference link 1
Step 2 Created Ionic 2 project( created with this basic steps )
Step 3 JavaScript file in plugin was not able to refer and access in Ionic2 .
After googling , I found this discussion , where it is told to create interface in plugin itself because of the following reason.
import {myPluginName} from '../../../plugins/xxx/*.js'
Will not work because the plugin is not part of the ionic native bundle.
If you have a custom plugin, you can do a few things.
1) Make a PR to add it to ionic-native proper
2) Use the raw plugin API.
You can use the raw plugin API without having it be part of Ionic Native.
The plugin is on the window object, so you would target the api normally
window.plugin.myPlugin.myMethod()
According to the GITHUB Example project this way the interface should be implemented
interface CordovaPlugins {
ZPLPrinter: ZPLPrinter;
}
interface ZPLPrinter {
print(
ipaddress: string,
bclabels: any,
printSuccess: (ip: string, labels: string[]) => void,
printError: (message: string) => void): void;
}
Now I created a similar interface in my plugin which is the following in plugin's www folder
interface CordovaPlugins {
Communicator: Communicator;
}
interface Communicator {
getInfo(successCallback: any, errorCallback: any);
}
This interface would ideally target this method in JS file
Device.prototype.getInfo = function(successCallback, errorCallback) {
console.log("device.js: getInfo function called");
argscheck.checkArgs('fF', 'Device.getInfo', arguments);
exec(successCallback, errorCallback, "Device", "getDeviceInfo", []);
};
Now I am stuck , as my Ionic project is not having typings folder itself.
In the sample Github Project, cordova packages are referred using typings folder . TypeScript File in project is referring Cordova using index.t.js
Import used to refer should go like
declare var cordova: Cordova;
Doubts:
Am I in the wright direction of the process
Is this the way to create Cordova plugin and use in ionic
Why I am not able to get typings folder in Ionic2
EDIT 1:
After just adding the plugin without even referring in Ionic project, I tried to run in Android device. But it gave me the following error.
Main error is this
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ionicframework.cutepuppypics234138/com.ionicframework.cutepuppypics234138.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference
Why would this error be causing? Detailed logs have given below
12-08 16:10:49.079 20555-20555/? E/ApkAssets: Error while loading asset assets/natives_blob_64.bin: java.io.FileNotFoundException: assets/natives_blob_64.bin
12-08 16:10:49.079 20555-20555/? E/ApkAssets: Error while loading asset assets/snapshot_blob_64.bin: java.io.FileNotFoundException: assets/snapshot_blob_64.bin
12-08 16:10:49.682 20555-20555/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ionicframework.cutepuppypics234138, PID: 20555
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ionicframework.cutepuppypics234138/com.ionicframework.cutepuppypics234138.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2339)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2413)
at android.app.ActivityThread.access$800(ActivityThread.java:155)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.apache.cordova.CordovaPlugin.privateInitialize(java.lang.String, org.apache.cordova.CordovaInterface, org.apache.cordova.CordovaWebView, org.apache.cordova.CordovaPreferences)' on a null object reference
at org.apache.cordova.PluginManager.getPlugin(PluginManager.java:171)
at org.apache.cordova.PluginManager.startupPlugins(PluginManager.java:97)
at org.apache.cordova.PluginManager.init(PluginManager.java:86)
at org.apache.cordova.CordovaWebViewImpl.init(CordovaWebViewImpl.java:115)
at org.apache.cordova.CordovaActivity.init(CordovaActivity.java:149)
at org.apache.cordova.CordovaActivity.loadUrl(CordovaActivity.java:224)
at com.ionicframework.cutepuppypics234138.MainActivity.onCreate(MainActivity.java:39)
at android.app.Activity.performCreate(Activity.java:6010)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2292)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2413)
at android.app.ActivityThread.access$800(ActivityThread.java:155)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
12-08 16:10:49.879 20656-20656/? E/SubDex: SubDex Config : .dex 2
12-08 16:10:50.285 20656-20656/? E/project: extsdcard==/storage/emulated/0/Android/data/com.cleanmaster.mguard/files
12-08 16:10:50.303 20656-20656/? E/project: extsdcard==/storage/emulated/0/Android/data/com.cleanmaster.mguard/files
After many trial and errors I found the solution.
I am putting down below details for future reference to any one who is trying a similar stuff!
Issues with code was as follows (my plugin name is Inject)
Inject\www\Inject.js was not having essential function for installing the plugin
Any method name mentioned in Inject.js should be same till Inject\src\Inject.java as there are options in execute method to refer different method name based on tag's received
Steps:
Use plugman to create skeleton of plugin Reference Link
Instead of using names like cordova-plugin-am-i-late , use cordova.plugin.Inject . I faced compile/run time issues using - symbol
Add targeted platform plugman platform add --platform_name android
Verify plugin.xml comparing the same reference
Include permissions in plugin.xml if required
Now verify Inject.js its missing essential method calls. Currently its having only the following code.
var exec = require('cordova/exec');
exports.coolMethod = function(arg0, success, error) {
exec(success, error, "Inject", "coolMethod", [arg0]);
};
But we need to include below also to make it install and work
function Inject(){
}
Inject.install = function () {
if (!window.plugins) {
window.plugins = {};
}
window.plugins.Inject = new Inject();
return window.plugins.Inject;
};
cordova.addConstructor(Inject.install);
For example I am targeting to show a Toast message for which below is my complete Inject.js file
function Inject(){
}
Inject.prototype.coolMethod = function (options, successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "Inject", "coolMethod", []);
};
Inject.install = function () {
if (!window.plugins) {
window.plugins = {};
}
window.plugins.Inject = new Inject();
return window.plugins.Inject;
};
cordova.addConstructor(Inject.install);
Now lets implement our Inject.java
public class Inject extends CordovaPlugin {
private static final int GRAVITY_CENTER = Gravity.CENTER_VERTICAL|Gravity.CENTER_HORIZONTAL;
private static final String TAG = "InjectCordovaPlugin";
String messageReceived;
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
Log.v(TAG, "execute , action =" + action);
if (action.equals("coolMethod")) {
String message = args.getString(0);
Log.v(TAG, "coolMethod called with message =" + message);
this.coolMethod(message, callbackContext);
return true;
}
return false;
}
private void coolMethod(String message, CallbackContext callbackContext) {
Log.v(TAG, "Inject's coolMethod called ,message="+message);
messageReceived = message;
if (message != null && message.length() > 0) {
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
final android.widget.Toast toast = android.widget.Toast.makeText(
cordova.getActivity().getWindow().getContext(),
messageReceived,
android.widget.Toast.LENGTH_LONG
);
toast.setGravity(GRAVITY_CENTER, 0, 0);
toast.show();
}
});
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
}
Just to make this clear I'm putting out my final plugin.xml
<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova.plugin.Inject"
version="1"
xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<name>Inject</name>
<js-module name="Inject" src="www/Inject.js">
<clobbers target="window.plugins.Inject"/>
</js-module>
<platform name="android">
<config-file parent="/*" target="res/xml/config.xml">
<feature name="Inject">
<param name="android-package"
value="cordova.plugin.Inject.Inject" />
</feature>
</config-file>
<config-file parent="/*" target="AndroidManifest.xml">
</config-file>
<source-file src="src/android/Inject.java"
target-dir="src/cordova.plugin.Inject/Inject" />
</platform>
</plugin>
Now create a sample Ionic2 project and add Android/IOS platform
Add the created plugin using cordova plugin add command
Navigate to ionic project in Nodejs command prompt and give this command (refer Plugin folder base after add ) cordova plugin add D:\PluginTrial\Inject
The added plugin should be populated under Ionic2Project\plugins folder
Call this function using window object. Below is my home.ts
import { Component } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
declare var window: any;
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController, private platform: Platform) {
}
showToast(message, position) {
this.platform.ready().then(() => {
window.plugins.Inject.coolMethod(message, "short", position);
});
}
}
Now refer this showToast method in home.html file
<button ion-button (click)="showToast('Yo Man! Its working ', 'center')">Default</button>
That's it. You should be able to test the plugin successfully! Happy Coding
Reference:
Reference One , Reference Two , Reference Three
Your plugin needs to look like this:
In: /[custom plugin name]/js/custom_plugin.js
var CustomPlugin = function(){};
CustomPlugin.someFunction = function(){
console.log("someFunction starts");
return new Promise(function(resolve,reject){
cordova.exec(
resolve,
reject,
[PLUGIN_NAME],
[ACTION_ON_NATIVE_SIDE],
[]
);
});
console.log("someFunction stops");
}
.... more functions
module.exports = CustomPlugin;
In: /[custom plugin name]/src/[android]||[ios] , the classes with native code.
And in: /[custom plugin name]/plugin.xml (this is an example, settings have to be adjusted to your case):
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="[CustomPlugin]"
version="1.0.0">
<name>CustomPlugin</name>
<description>...</description>
<license>...</license>
<author>...</author>
<engines>
<engine name="cordova" version=">=6.0.0" />
</engines>
<js-module src="www/js/custom_plugin.js" name="CustomPlugin">
<clobbers target="CustomPlugin" />
</js-module>
<platform name="ios">
<config-file target="config.xml" parent="/*">
<preference name="orientation" value="portrait"/>
<feature name="CustomPlugin">
<param name="ios-package" value="CustomPlugin" />
<param name="onload" value="true"/>
</feature>
</config-file>
<header-file src="src/ios/CustomPlugin.h" />
<source-file src="src/ios/CustomPlugin.m" />
<!--framework src="QuartzCore.framework" />
<framework src="AssetsLibrary.framework" />
<framework src="CoreGraphics.framework" />
<framework src="MobileCoreServices.framework" /-->
</platform>
<platform name="android">
<config-file target="res/xml/config.xml" parent="widget">
<preference name="orientation" value="portrait"/>
<feature name="CustomPlugin" >
<param name="android-package" value="[package name].CustomPlugin"/>
<param name="onload" value="true"/>
</feature>
</config-file>
<config-file target="AndroidManifest.xml" parent="/*">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="..." />
<uses-feature android:name="..." />
</config-file>
<source-file src="src/android/CustomPlugin.java" target-dir="[package folder directory organization like: com.android.something]" />
<source-file ... />
<source-file src="src/android/custom_plugin.xml" target-dir="res/layout" />
</platform>
</plugin>
then you add you plugin with the CLI: ionic plugin add [folder of your plugin]
In your Ionic project, in the classes (angular2 directives) where you want to use your plugin, write before the #Component section: declare var CustomPlugin: any;. Then in that class, you can use your plugin by refering to CustomPlugin that is exported with module.exports = CustomPlugin;
from the file: /[custom plugin name]/js/custom_plugin.js.
TO ANSWER EDIT 1 OF THE QUESTION, HERE SOME DETAILS OF THE ANDROID PART:
In the android plugin project (once platform android has been added and built at least once, with ionic CLI), in android studio (2.2.2), when looking at the build project under "[my project]\platforms\android":
In the hierarchy, the MainActivity file is autogenerated under:
"android\java\com\ionicframework.[my project name + a large number]\MainActivity":
package com.ionicframework.[my project name + a large number];
import android.os.Bundle;
import org.apache.cordova.*;
public class MainActivity extends CordovaActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// enable Cordova apps to be started in the background
Bundle extras = getIntent().getExtras();
if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
moveTaskToBack(true);
}
// Set by <content src="index.html" /> in config.xml
loadUrl(launchUrl);
}
}
For my custom plugin (not going into details here) under "android\java[package of the custom plugin]:
package [package of the custom plugin];
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
// + other imports needed
public class CustomPlugin extends CordovaPlugin {
private static CallbackContext customDeferredCallback;
public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
//all the thing corresponding to your case need to end if with either:
// if OK: callbackContext.success(); return true; ;
// if not OK: callbackContext.error(error.getMessage()); return false;
// if JAVA returns a result to JS do: actionBindListener(callbackContext);
}
private boolean actionBindListener(final CallbackContext callbackContext){
cordova.getThreadPool().execute(new Runnable() {
public void run(){
try{
customDeferredCallback= callbackContext;
}catch(Exception e){e.printStackTrace();}
}
});
return true;
}
//in your program when you get the result you want to send back to javascript call this function
public static void sendResultToJS(res){
JSONObject eventData = new JSONObject();
try {
eventData.put("CUSTOM_KEY", res);
} catch (JSONException e) {
e.printStackTrace();
}
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, eventData);
pluginResult.setKeepCallback(true);
try{
customDeferredCallback.sendPluginResult(pluginResult);
} catch(NullPointerException e){
e.printStackTrace();
}
}
}
And finally android\manifests\manifests.xml looks like that:
<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" package="com.ionicframework.[project name + large number]" xmlns:android="http://schemas.android.com/apk/res/android">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:hardwareAccelerated="true" android:icon="#mipmap/icon" android:label="#string/app_name" android:supportsRtl="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="#string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="#android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="#string/launcher_name">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:exported="true" android:name="com.adobe.phonegap.push.PushHandlerActivity" />
<receiver android:name="com.adobe.phonegap.push.BackgroundActionButtonHandler" />
<receiver android:exported="true" android:name="com.google.android.gms.gcm.GcmReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<service android:exported="false" android:name="com.adobe.phonegap.push.GCMIntentService">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service android:exported="false" android:name="com.adobe.phonegap.push.PushInstanceIDListenerService">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service android:exported="false" android:name="com.adobe.phonegap.push.RegistrationIntentService" />
</application>
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" />
</manifest>
As far as typings is concerned, it is no longer used. All or most typescript declarations are moved to npm itself and you install them as npm install #types/package_name.
https://www.npmjs.com/~types
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.md
If you need typings folder you could try
npm install typings
you can also referance type declararions through
// <reference path="" />
in typescript