expo-updates not updating internal distribution - expo

Trying to implement expo-updates and I'm a bit stumped. I have a deployment, channel and branch all called "testing". I have a good internal distribution build for both OSes, and can verify that the app configuration has updates.url. I have a successfully run eas update --channel testing, which shows up in the UI under "updates" and linked to the "testing" branch & channel.
I've force-quit the app a dozen times and still do not see the update. Do I have to implement something in the codebase for this to "take", or does Expo handle this automatically?
eas.json parts:
{
...
"build": {
"testing": {
"channel": "testing",
"distribution": "internal",
},
...
},
...
}
Expo Build output parts:
{
"runtimeVersion": {
"policy": "sdkVersion"
},
"updates": {
"url": "https://u.expo.dev/<projectId>"
},
...
}

I ended up having to do something like this to get updates to work:
useEffect(() => {
if (!__DEV__) {
async function checkForUpdates() {
let update: Updates.UpdateCheckResult;
try {
update = await Updates.checkForUpdateAsync();
} catch (e) {
throw new Error('Error checking for updates', e);
}
if (update.isAvailable) {
setLoading(true);
try {
const fetchResult = await Updates.fetchUpdateAsync();
setIsNew(fetchResult.isNew);
} catch (e) {
setLoading(false);
throw new Error('Error fetching updates', e);
}
try {
await Updates.reloadAsync();
} catch (e) {
setLoading(false);
throw new Error('Error reloading app', e);
}
setLoading(false);
}
}
checkForUpdates();
}
}, []);

Related

expo-task-manager with expo-location error

Please provide the following:
SDK Version: "expo": "^45.0.0",
IOS Emulator (atm) but all normally.
expo-task-manager & expo-location
Hello, We are setting up background location tracking in our App...
I am defining my background location task before is loaded
BackgroundLocation.ts
export const LOCATION_TASK_NAME = 'background-location-task'
function init() {
TaskManager.defineTask(LOCATION_TASK_NAME, _execute)
setTimeout(() => {
TaskManager.getRegisteredTasksAsync().then((tasks) =>
console.log('registered tasks', tasks) // logs empty array
)
}, 5000)
}
export default { init }
App.tsx
import BackgroundLocation from '../../......'
BackgroundLocation.init()
export default App() { ... }
Now in the App component hiararchy i have a Component called <LocationTracker />
import { LOCATION_TASK_NAME } from '../../BackgroundLocation'
...
React.useEffect(() => {
async function handleLocation() {
try {
if (backgroundLocationServicesEnabled) {
await Location.startLocationUpdatesAsync(
LOCATION_TASK_NAME,
{
accuracy: Location.Accuracy.Balanced,
distanceInterval: 20,
}
)
} else {
await Location.stopLocationUpdatesAsync(
LOCATION_TASK_NAME
).catch((e) => {
console.error(
'error calling stopLocationUpdatesAsync',
e
)
})
}
} catch (e) {
console.error('error in handleLocation', e)
}
}
handleLocation().then(() => {})
}, [backgroundServicesEnabled])
Background location is not enabled in my case so the error being fired is
error calling stopLocationUpdatesAsync, [Error: Task 'background-location-task' not found for app ID 'mainApplication'.]
at components/LocationTracker.tsx:70:37 in Location.stopLocationUpdatesAsync._catch$argument_0
its this part
[Error: Task 'background-location-task' not found for app ID 'mainApplication'.]
that is causing me confusion because i'm registering that task ID right at the begining of the app.
OP over here https://forums.expo.dev/t/expo-task-manager-with-expo-location-error/68515

Mocha tests, clean disk database before every file runs

I am using Sails 1.x.
Is it possible to reset the Sails.js database before each test file runs? I want it to be in state after sails.lift() completes before each run. I followed the docs here - https://sailsjs.com/documentation/concepts/testing - but did not end up with any solution like this.
The only solution I'm having right now is to change the lifecyle.test.js before and after to run beforeEvery and afterEvery - https://sailsjs.com/documentation/concepts/testing - so this is lifting everytime before test. But it takes a long time to lift.
This is very simple to do. You just need to specify to add test connection in your connections on datasourses (depends on the version of Sails.js), setup it as active during the test and provide migration strategy 'drop' which is just rebuild your DB every time on startup
models: {
connection: 'test',
migrate: 'drop'
},
My connections Sails.js 0.12.14
module.exports.connections = {
prod: {
adapter: 'sails-mongo',
host: 'localhost',
port: 27017,
database: 'some-db'
},
test: {
adapter: 'sails-memory'
},
};
My simplified lifecycle.test.js
let app;
// Before running any tests...
before(function(done) {
// Lift Sails and start the server
const Sails = require('sails').constructor;
const sailsApp = new Sails();
sailsApp.lift({
models: {
connection: 'test',
migrate: 'drop'
},
}, function(err, sails) {
app = sails;
return done(err, sails);
});
});
// After all tests have finished...
after(async function() {
// here you can clear fixtures, etc.
// (e.g. you might want to destroy the records you created above)
try {
await app.lower()
} catch (err) {
await app.lower()
}
});
In Sails 1 it's even simpler
const sails = require('sails');
before((done) => {
sails.lift({
datastores: {
default: {
adapter: 'sails-memory'
},
},
hooks: { grunt: false },
models: {
migrate: 'drop'
},
}, (err) => {
if (err) { return done(err); }
return done();
});
});
after(async () => {
await sails.lower();
});
I'm using this in my bootstrap test file to make the database clean.
const sails = require('sails');
before((done) => {
sails.lift({
log: {
level: 'silent'
},
datastores: {
default: {
adapter: 'sails-disk',
inMemoryOnly: true
}
},
models: {
migrate: 'drop',
archiveModelIdentity: false
}
}, function (err, sails) {
if (err) return done(err);
done(err, sails);
});
});
after(async () => {
await sails.lower();
});
beforeEach((done) => {
sails.once('hook:orm:reloaded', done);
sails.emit('hook:orm:reload');
});

Firebase + Phonegap plugin push: How to send silent messages but update app?

My current stack is:
Django using FCM to send push notifications to an Ionic app. The app uses the phonegap-plugin-push.
I have the problem, that the on notification handler doesn't get called.
Here is the data that I'm sending:
'message': {
'token': '<my-device-token>',
'data': {
'yup': 'okay'
},
'apns': {
'payload': {
'aps': {
'data': 'here is my data',
'badge': 1,
'content-available': 1
},
'notId': 2
}
}
}
The app gets the data, but somehow the on notificatoin handler doesn't get called.
Also here is my code in the app:
import { Injectable } from '#angular/core';
import { Push, PushObject, PushOptions } from '#ionic-native/push';
import { AlertController, Platform } from 'ionic-angular';
import { FcmDataProvider } from './fcm.data';
#Injectable()
export class FcmProvider {
/*
* FIREBASE CLOUD MESSAGING
*/
constructor(private push: Push,
private alertCtrl: AlertController,
private platform: Platform,
private fcmDataProv: FcmDataProvider) {
}
getPermission(): Promise<{isEnabled: boolean}> {
// Listen for res.isEnabled.
return this.push.hasPermission();
}
initPush() {
console.log("Init push!");
const options: PushOptions = this.initPushOptions();
const pushObject: PushObject = this.push.init(options);
pushObject.on('notification').subscribe((notification: any) => {
console.log('Received a notification', notification);
if(this.platform.is('ios')) {
this.handleIOSNotification(notification, pushObject);
} else if(this.platform.is('android')) {
this.handleAndroidNotification(notification);
}
this.presentSuccessAlert(notification.message);
});
pushObject.on('registration').subscribe(
(registration: any) => {
console.log('Device registered', registration);
// TODO: Send registration.registrationId to server and update it.
}
);
pushObject.on('error').subscribe(
error => console.error('Error with Push plugin', error)
);
}
private initPushOptions(): PushOptions {
return {
android: {
sound: true,
vibrate: true,
clearBadge: true
},
ios: {
alert: true,
badge: true,
sound: true,
clearBadge: true
},
windows: {}, // Lol
browser: {
pushServiceURL: 'http://push.api.phonegap.com/v1/push'
}
};
}
private handleIOSNotification(data, push: PushObject) {
push.finish().then(
() => console.log("Finished processing push data")
).catch(() => console.error(
"Something went wrong with push.finish for ID=", data.additionalData.notId
));
}
private handleAndroidNotification(data) {
console.log(data.data);
}
private presentSuccessAlert(message: string): void {
let alert = this.alertCtrl.create({
title: "Neue Benachrichtigung",
message: message,
buttons: ["Ok"]
});
alert.present();
}
}
I'm testing on iOS but I would love to know how to handle it on android as well.
Edit:
Here is the console.log I receive from XCode:
Push Plugin notId 1
Warning: Application delegate received call to -application:didReceiveRemoteNotification:fetchCompletionHandler: but the completion handler was never called.
Notification received
Push Plugin key: content-available
Push Plugin key: data
Push Plugin key: badge
Wow this issue is super silly.
But here is what was wrong: You got to put notId first!
Like this:
"notId": 1, # notId HAS TO BE FIRST!!!
'aps': {
'data': 'here is my data',
'content-available': 1,
}

Delay in retrieving data from Ionic 2 storage

Before I launches the app I will check with local storage if any user data available, If yes I will navigation to Home page else Login page.
Here I'm unable to retrieve stored data, Any inputs please...
Currently using Ionic 2 SQlite plugin.
Note: In browser it's working fine but on Android device it's not working.
app.component.ts : checking user data
loadUser() {
this.userSettings.getUser().then(user => {
this.userObj = JSON.stringify(user);
if (user) {
console.log('App : ', this.userObj);
this.nav.setRoot(HomePage,this.userObj);
} else {
console.log('App : No user data');
this.rootPage = LoginPage;
}
});
}
login.ts : Saving user data
this.userSettings.addUser(
userData.employeeCode,
userData.password,
userData.role
);
user-settings.ts : Storage file in providers
getUser() {
if (this.sql) {
return this.sql.get('user').then(value => value);
} else {
return new Promise(resolve => resolve(this.storage.get('user').then(value => value)));
}
}
addUser(employeeCode, password, role) {
let item = { employeeCode: employeeCode, password: password, role: role };
if (this.sql) {
this.sql.set('user', JSON.stringify(item)).then(data => {
this.events.publish('userObj:changed');
});
} else {
return new Promise(resolve => {
this.storage.set('user', JSON.stringify(item)).then(() => {
this.events.publish('userObj:changed');
resolve();
});
});
}
}
app.module.ts:
providers: [
{ provide: ErrorHandler, useClass: IonicErrorHandler },
AuthService,
SqlStorage,
UserSettings,
Storage
]
Thanks in advance.
Problem solved
After calling the sqlite operation in ngAfterViewInit it's working fine.
ngAfterViewInit() {
this.storage.get('user').then((user: any) => {
if (user) {
this.userCredentials = JSON.parse(user);
this.nav.setRoot(HomePage, this.userCredentials);
}
else {
this.rootPage = LoginPage;
}
});
}
[Source] (https://github.com/driftyco/ionic-conference-app/blob/master/src/pages/account/account.ts)
Cheers :)
As you point out that your code is working in Chrome, but not on your device, you might be calling sqlite before cordova's device.ready() has fired.
In app.component.ts ensure you call this.loadUser() in the following manner: (platform.ready() should already be in the constructor)
platform.ready().then(() => {
this.loadUser();
});

Ionic2 proxies not working with ionic run but working with ionic serve?

For my ionic.config.json I have:
{
"name": "TSICMobile",
"app_id": "6e4680fa",
"typescript": true,
"v2": true,
"proxies": [
{
"path": "/api",
"proxyUrl": "http://192.168.0.105:8081/api"
}
]
}
In my provider (user-data.ts, based on Ionic2 conference app) I have for example:
login(credentials) {
return new Promise((resolve, reject) => {
this.http.post(
'/api/Login',
JSON.stringify(credentials),
{ headers: this.contentHeader }
).subscribe(res => {
console.log('api/Login return');
this.data = res.json();
if (this.data.authenticated === true) {
this.storage.set('TSIC_USER_PROFILE', JSON.stringify(this.data.tsiC_USER_PROFILE));
this.storage.set('TSIC_USER_ROLES', JSON.stringify(this.data.listRoles));
this.storage.set('tsic_id_token', this.data.token);
this.events.publish('user:login');
resolve(true);
} else {
reject('not authenticated');
}
}, error => {
console.log('api/Login failed');
reject(error);
});
});
}
when running:
ionic serve --lab -c
the proxy works perfectly and posts to http://192.168.0.105:8081/api/Login
when running
ionic run android -c
the post url is file://api/Login, and obviously fails.
Need assistance in understanding why (seemingly), the proxy is not in effect when running on device, and what I may be doing wrong or not understanding.
You don't need a proxy when you are on your device because ionic can handle the cors there. You need the proxy on serve because the browser is trying to handle the CORS and its more strict with it.
What I suggest you do is check if window.cordova exists and if it does use the normal url and otherwise the proxy url.
Like this:
login(credentials) {
return new Promise((resolve, reject) => {
this.http.post(
window.cordova?:'http://192.168.0.105:8081/api/Login':'/api/Login':,
JSON.stringify(credentials),
{ headers: this.contentHeader }
).subscribe(res => {
console.log('api/Login return');
this.data = res.json();
if (this.data.authenticated === true) {
this.storage.set('TSIC_USER_PROFILE', JSON.stringify(this.data.tsiC_USER_PROFILE));
this.storage.set('TSIC_USER_ROLES', JSON.stringify(this.data.listRoles));
this.storage.set('tsic_id_token', this.data.token);
this.events.publish('user:login');
resolve(true);
} else {
reject('not authenticated');
}
}, error => {
console.log('api/Login failed');
reject(error);
});
});
}
Short answer is the proxy is really only useful for ionic serve. For ionic run you need to use cordova-plugin-whitelist
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-whitelist/
What this means for you though is, you'll have to swap your URIs during build. So instead of just /api/myAwesomeService you'll actually have http://192.168.0.105:8081/api as your URI when running on a real device.
this official article exactly shows you how to deal with this situation.
http://blog.ionic.io/handling-cors-issues-in-ionic/
an easier way is defining a Constant just like this:
.constant('SERVER', {
// when not using proxy
//url: 'https://myextsite.com/api/public/index.php/v1'
// when using proxy
url: 'v1'
})
ref: https://forum.ionicframework.com/t/solved-ionicview-app-http-request-to-external-api/18696/3