Huawei HMS maps not working on Ionic Capacitor runtime - ionic-framework

I have followed this guide to add Huawei HMS maps to my IONIC capacitor runtime app.
https://github.com/HMS-Core/hms-cordova-plugin/tree/master/cordova-plugin-hms-map/example/ionic
This app has google-services.json and huawei agconnect-services.json.
In project build.gradle I'm using
[...]
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
capacitor.build.gradle
dependencies {
[...]
implementation "com.huawei.hms:base:5.2.0.300"
implementation "com.huawei.hms:maps:6.0.1.304"
}
Here are the npm libs
npm install #hmscore/cordova-plugin-hms-map#latest
npm install #ionic-native/core #hmscore/ionic-native-hms-map#latest
Set the appropriate sha2 figerprint in the Huawei developer console. App build.gradle.
signingConfigs {
config {
storeFile file('huawei.jks')
storePassword '*****'
keyAlias 'mapshowcase'
keyPassword '*****'
}
}
dependencies {
[...]
implementation 'com.huawei.agconnect:agconnect-core:1.5.2.300'
}
async initMap() {
const mapOptions = {
mapType: MapType.MAP_TYPE_TERRAIN,
cameraPosition: {
target: {lat: 40.7587658, lng: 30.3146964},
zoom: 2
}
};
this.hmsMap.requestPermission();
this.map = await this.hmsMap.getMap('map', mapOptions, {marginTop: 50});
this.addListener();
this.map.setMyLocationEnabled(true);
this.map.getUiSettings().setMyLocationButtonEnabled(true);
this.map.getProjection().getVisibleRegion().then(vr => console.log(JSON.stringify(vr)));
this.map.getProjection().toScreenLocation({lat: 12, lng: 43}).then(point => console.log(JSON.stringify(point)));
this.map.getProjection().fromScreenLocation({x: 300, y: 600}).then(latLng => console.log(JSON.stringify(latLng)));
}
Testing on a Huawei Harmony OS phone, but geting this error.
E/HmsMapKit_ErrorTraceLogPusher_4: cache error trace log : ErrorTraceLogDTO{ scenario = ACCESS_SERVICE_ERROR', message='5 : Unknown Code - 5'}
com.huawei.hms.maps.foundation.client.mac: * * *n*n*w* *o*e*-*5
at com.huawei.hms.maps.foundation.client.mac$maa.b(Unknown Source:25)
at com.huawei.hms.maps.foundation.client.mab.a(Unknown Source:20)
at com.huawei.hms.maps.foundation.client.mab.c(Unknown Source:80)
at com.huawei.hms.maps.foundation.client.mab.a(Unknown Source:88)
at com.huawei.hms.maps.provider.client.tile.maa.a(Unknown Source:1)
at com.huawei.hms.maps.provider.client.tile.maa.lambda$gI3f4RyIuh0G4Qoia5V0XosFnEE(Unknown Source:0)
at com.huawei.hms.maps.provider.client.tile.-$$Lambda$maa$gI3f4RyIuh0G4Qoia5V0XosFnEE.call(Unknown Source:6)
at com.huawei.hms.maps.foundation.client.mab$maa.a(Unknown Source:3)
at com.huawei.hms.maps.provider.client.tile.maa.c(Unknown Source:23)
at com.huawei.hms.maps.provider.client.tile.maa.a(Unknown Source:4)
at com.huawei.hms.maps.provider.cache.mag.a(Unknown Source:63)
at com.huawei.hms.maps.provider.cache.mag$mac.startUrlRequest(Unknown Source:2)
at com.huawei.map.MapController.startUrlRequest(Unknown Source:28)
Fo far I have not found any solution or details about such error on internet. Any help is appreciated.
Update 1
Looks like the map is properly constructed:
I/Capacitor/Console: File: http://localhost/ - Line 6588 - Msg: Huawei map constructed with the div id map :: and the props 1
But the target map div stays in blank and when I tap on it I'm able to see the clicks being logged.
addListener() {
const log = document.getElementById('log');
this.map.on(MapEvent.ON_MAP_CLICK, (latLng) => {
log.innerHTML = '<br>' + 'Map_Click:' + latLng.lat + '<-->' + latLng.lng + log.innerHTML;
});
this.map.on(MapEvent.ON_MAP_LONG_CLICK, (latLng) => {
log.innerHTML = '<br>' + 'Map_Long_Click:' + latLng.lat + '<-->' + latLng.lng + log.innerHTML;
});
}
Update 2
The issue is with the transparency of the parent div of the map div. The plugin does not set the background transparent to all its parent nodes automatically on map init.

The issue was solved by setting all map div's parent ion-content nodes'css value when map has to be shown and remove it when map page is destroyed.
global.scss
--ion-background-color: var(--map-background, white);
.background-transparent {
--map-background: transparent !important;
}
Map.page.ts
ionViewDidEnter(){
document.body.classList.toggle('background-transparent', true);
}
ionViewWillLeave(){
document.body.classList.toggle('background-transparent', false);
}

The provided log is not enough.
It is better to create ticket here: https://developer.huawei.com/consumer/en/support/feedback/#/
And put all the log file in the ticket.
Or you can search "HmsMap" and share the search result here.

Related

OneSignal issue for Ionic 6 & Capacitor

I'm trying to set OneSignal for push notifications on devices.
I did the step by step to setup methods which are shown in the OneSignal Documentation, but no luck.
I also did the official Ionic - Capacitor - Cordova methods to setup OneSignal, with no luck again.
This is the first method I did, following Ionic official Docs:
app.module.ts
...
import { OneSignal } from '#awesome-cordova-plugins/onesingal';
#NgModule({
...
providers: [OneSignal]
});
I created a PushService where I include methods from OneSignal.
push.service.ts:
import { OneSignal } '#awesome-cordova-plugins/onesignal';
export class PushService {
constructor ( private signal: OneSignal ) {}
start (): void {
this.signal.startInit ( 'MY_ONESIGNAL_APP_ID', 'FIREBASE_ID' );
this.signal.handleNotificationReceived().subscribe(() => {
// do something when notification is received
});
...
this.signal.endInit();
}
}
I call "start" method on my app.component.ts, initializing on this.platform.ready...
And when I test on my device, the answer from debug is "plugin_not_installed" OneSignal
Second method I use, following instructions from the Official OneSignal Docs "Ionic & Capacitor"
Directly I put methods on my "start" in push.service.ts, I didn't call it on app.module.ts because is a function:
import { OneSignal } from 'onesignal-cordova-plugin';
export class PushService {
constructor () {}
start (): void {
OneSignal.setAppId ( 'ONESIGNAL_APP_ID' );
...
OneSignal.setNotificationWillShowInForegroundHandler ( ( d ) => console.log ( d ) );
}
}
In this case, the error is "TypeError: Cannot read properties of undefined (reading 'setAppId')"
So, any of those methods is not working.
My system info develop is:
Ionic:
Ionic CLI : 6.18.1 (C:\Users\user\AppData\Roaming\npm\node_modules\#ionic\cli)
Ionic Framework : #ionic/angular 6.0.1
#angular-devkit/build-angular : 13.1.2
#angular-devkit/schematics : 12.2.13
#angular/cli : 13.1.2
#ionic/angular-toolkit : 5.0.3
Capacitor:
Capacitor CLI : 3.3.3
#capacitor/android : 3.3.3
#capacitor/core : 3.3.3
#capacitor/ios : not installed
Utility:
cordova-res : not installed globally
native-run : 1.5.0
System:
NodeJS : v16.13.1 (C:\Program Files\nodejs\node.exe)
npm : 8.2.0
OS : Windows 10
I think you need to install the plugin - this is what I have in package.json
"onesignal-cordova-plugin": "^3.0.1"
And import like this -
import OneSignal from 'onesignal-cordova-plugin';
And also in angular.json add this part with allowedCommonJsDependencies
{
"projects": {
"app": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {},
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"allowedCommonJsDependencies": [
"onesignal-cordova-plugin"
]
}
}
}
}
}
}
The official One Signal docs need improvement but they helped me to find the path to get push notifications working with Capacitor 3 and Ionic 6 using Vue on web mobile and also on Android. This is working on my projects.
The points of attention are these:
If you'll use mobile push or native push, you have to initialize Onesignal detecting the platform.
You also have to include Onesignal service worker js files somewhere they could be located by the browser.
// Call this function when your app start
function OneSignalInit() {
OneSignal.setAppId("xxxxx-xxxxxx-xxxxxx"); //Your APP ID
OneSignal.setNotificationOpenedHandler(function(jsonData) {
console.log('notificationOpenedCallback: ' + JSON.stringify(jsonData));
});
OneSignal.promptForPushNotificationsWithUserResponse(function(accepted) {
console.log("User accepted notifications: " + accepted);
});
}
if (getPlatforms().includes("capacitor")) {
OneSignalInit();
} else {
window.OneSignal = window.OneSignal || [];
window.OneSignal.push(function () {
// You have to include some JS files from Onesignal as the docs say to do
// Place them in a place findable by the browser when the URL is resolved
window.OneSignal.SERVICE_WORKER_PARAM = { scope: '/assets/js/onesignal/' };
window.OneSignal.SERVICE_WORKER_PATH = 'assets/js/onesignal/OneSignalSDKWorker.js'
window.OneSignal.SERVICE_WORKER_UPDATER_PATH = 'assets/js/onesignal/OneSignalSDKUpdaterWorker.js'
window.OneSignal.init({
appId: "xxxxx-xxxxx-xxxxx", //Your APP ID
safari_web_id: "web.onesignal.auto.xxxxxxxxxxx",
notifyButton: {
enable: false,
},
subdomainName: "odontoenlace",
promptOptions: {
slidedown: {
prompts: [
{
type: "push", // current types are "push" & "category"
autoPrompt: true,
text: {
/* limited to 90 characters */
actionMessage: "Nos gustaría enviarte notificaciones para que estés al tanto de eventos en tu perfil.",
/* acceptButton limited to 15 characters */
acceptButton: "Aceptar",
/* cancelButton limited to 15 characters */
cancelButton: "Cancelar"
},
delay: {
pageViews: 0,
timeDelay: 1
}
}
]
}
}
});
});
}
After all that, you can use this code to detect if Onesignal is recognized and get your Onesignal user_id also known as player_id. Again, checking if you are on web or native.
if (getPlatforms().includes("capacitor")) {
OneSignal.setAppId("xxxxx-xxxxx-xxxxxx"); // Your APP ID
OneSignal.getDeviceState((stateChanges) => {
console.log(
"OneSignal getDeviceState: " + JSON.stringify(stateChanges)
);
if (stateChanges && stateChanges.hasNotificationPermission) {
console.log("Player ID: " + stateChanges.userId);
} else {
console.log("Push notifications are disabled");
}
});
} else {
console.log("Platform is not capacitor");
is_push_supported.value =
window.OneSignal.isPushNotificationsSupported();
if (is_push_supported.value) {
if (!getPlatforms().includes("capacitor")) {
window.OneSignal.getUserId((userId) => {
console.log("Player ID: " + userId);
});
}
}
}
Finally, if you're compiling your app, Capacitor's default settings for release mode, suppress externals Onesignal libraries so check on your build.gradle file that you have disabled proguard, and minifyEnabled is set to false. The best way is to leave empty the relase object
buildTypes {
release {
}
}

Ionic v5 web media capture with capacitor - cordova_not_available

I am building an app with Ionic 5, Capacitor 2 and Angular 11.
I need to capture video and audio using the media capture cordova plugin.
I installed the following modules:
npm install cordova-plugin-media-capture
npm install #ionic-native/media-capture
And added MediaCapture to the providers of my app module.
Then I call mediaCapture.captureVideo() to retrieve a video ; unfortunately an exception is thrown when testing on a browser: cordova_not_available
The github repo states this plugin is web-compatible, and its sources have a browser implementation. However the window.navigator.device.capture is missing to make this plugin work.
Is it a bad configuration from my side? Or this cordova plugin wouldn't be compatible with capacitor?
I made a repro : https://stackblitz.com/edit/ionic-v5-media-capture-capacitor?file=src/app/app.component.ts
Thank you for your help
I wrote a regular Angular version for the web, if anyone need it:
async browserCapture() {
const stream: MediaStream = await navigator.mediaDevices.getUserMedia(this.constraints);
const recorder = new MediaRecorder(stream, {mimeType: 'ogg'});
const chunks: Blob[] = [];
recorder.ondataavailable = (event: BlobEvent) => {
if (event.data && event.data.size > 0) {
chunks.push(event.data);
this.zone.run(() => {
this.recordChunks = [...chunks];
this.cd.markForCheck();
});
}
};
this.recorder.onstop = () => {
this.zone.run(() => {
stream.getTracks().forEach(t => t.stop());
if (chunks?.length) {
this.upload(new Blob(chunks, {type: 'ogg'})); // use the blob result
}
});
};
recorder.start(500);
}

Recorded file neither saving nor playing in cordova-plugin-media (Error code 1)

I'm using this plugin: cordova-plugin-media with ionic capacitor instead of cordova with command ionic cap sync.
My code:
audioFile: MediaObject;
constructor(private media: Media, private plt: Platform, private file: File) {}
ionViewDidEnter() {
this.plt.ready()
.then(() => {
setTimeout(() => {
this.audioFile = this.media.create(this.file.externalRootDirectory + 'audiofile.mp3');
this.audioFile.onStatusUpdate.subscribe(status => console.log('status: ', status));
this.audioFile.onSuccess.subscribe(() => console.log('Action is successful'));
this.audioFile.onError.subscribe(error => console.log('Error: ', error));
}, 1000);
})
.catch(err => console.log('ready error: ', err));
}
record() {
// When record button clicked
this.audioFile.startRecord();
}
stop() {
// When stop button clicked
this.audioFile.stopRecord();
this.audioFile.play();
}
When I clicked Record btn, record() was executed and output was: Error: 1 and when I stopped recording than the output was status: 4 and Action is successful
I expected to either play the recording or get audiofile.mp3 in the file manager of my android device but I didn't observed any of it. Can someone help me with this issue?
What I tried:
I thought that its extension issue so I tried replacing mp3 with 3gp and m4a
I tried removing file:// from file.externalRootDirectory with slice method - file.externalRootDirectory.slice(7)
Instead of externalRootDirectory I also tried applicationDirectory and externalDataDirectory
I also submitted my issue on their github repository but I didn't got any response yet
I tried finding solutions on other communities and stackoverflow itself but problem still exists
Android 10 uses a new file system therefore plugins that have not updated themselves might not read/create files on Android 10.
You need to manually add this line in your manifest file : android:requestLegacyExternalStorage="true"
Open your project in Android Studio and open the AndroidManifest file.
In tag inside your manifest file, add android:requestLegacyExternalStorage="true"
Rebuild your project

Unable to register the service worker

My app is under ionic 4 angular.
I've installed the pwa part with :
ng add #angular/pwa --project app
Then I build with : ionic build --prod
and deployed to firebase with : firebase deploy
But I have 2 problems :
1) the banner "add to screen" is not shown when I browse the app from my android phone.
Even with this code on the root url :
showBtn: boolean = false;
deferredPrompt;
constructor(private modalController: ModalController, public authUser: AuthUserService, private router: Router){}
ionViewWillEnter(){
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later on the button event.
this.deferredPrompt = e;
// Update UI by showing a button to notify the user they can add to home screen
this.showBtn = true;
});
//button click event to show the promt
window.addEventListener('appinstalled', (event) => {
alert('installed');
});
if (window.matchMedia('(display-mode: standalone)').matches) {
alert('display-mode is standalone');
}
}
2) When I launch lighthouse audit I get this warning :
Does not register a service worker that controls page and start_url
I've tried to uninstall, reinstall, rebuild everything but nothing works.
On ionic docs I can't find any clue to fix this problem.
After many days I was able to make it works.
First I add this following snippet to the firebase.json file to the hosting property:
{
"source": "ngsw-worker.js",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache"
}
]
}
Then I add this script in my index.html :
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('ngsw-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.error('Error', err));
}
</script>
Now it works !

Ionic native Transfer plugin's `file.dataDirectory` shows error

I'm going to use the Ionic native Transfer plugin as shown below.
Problem is here this.file.dataDirectory.It shows error like [ts] Property 'dataDirectory' does not exist on type 'File'..Can you tell me what is the solution for this?
download() {
const fileTransfer: TransferObject = this.transfer.create();
const url = 'http://www.example.com/file.pdf';
fileTransfer.download(url, this.file.dataDirectory + 'file.pdf').then((entry) => {
console.log('download complete: ' + entry.toURL());
}, (error) => {
// handle error
});
}
Oh.. My bad :(
I have to install File plugin too :D
$ ionic cordova plugin add cordova-plugin-file --save
$ npm install --save #ionic-native/file