Lighthouse scoring for progressive web app - progressive-web-apps

https://yourstop.info is a PWA. When I run lighthouse on it, the PWA score comes up as 73 and performance as 60, see image below.
It is giving a time to interactive of 19.1 seconds which is the reason for the low scoring. What happens on startup is that when the user's location is determined, a list of relevant bus stops is downloaded in the background. The code for this is
var firstLocationUpdate = false;
//var firstLocationUpdate = true;
if (navigator.geolocation) {
navigator.geolocation.watchPosition(updatePosition, showError, geoOptions);
}
else {
window.ys.userLocationError = "Geolocation is not supported by this browser";
}
function updatePosition(position) {
if (position != null) {
window.ys.userLat = position.coords.latitude;
window.ys.userLon = position.coords.longitude;
try {
// When google maps was not loaded this was throwing an exception
window.ys.userLocation = new google.maps.LatLng(window.ys.userLat, window.ys.userLon);
}
catch (e) {
console.log("Google maps not loaded when initializing geo.js, userLocation LatLng not set");
}
window.ys.userLocationError = "";
if (window.ys.userLocation != null && window.ys.userLocationTripMarker != null) {
window.ys.userLocationTripMarker.setPosition(window.ys.userLocation);
}
if (window.ys.userLocation != null && window.ys.userLocationSearchMarker != null) {
window.ys.userLocationSearchMarker.setPosition(window.ys.userLocation);
}
if (firstLocationUpdate == false) {
var event = document.createEvent("HTMLEvents");
event.initEvent('firstlocationupdate', true, true);
document.dispatchEvent(event);
firstLocationUpdate = true;
}
}
}
This does however not impact at all on the readiness of the PWA, the page is already fully rendered and the user can perform other tasks while the background function is in progress. If in the code snippet above, firstLocationUpdate is initialized to true and the background download is prevented, then the lighthouse scoring is much higher as shown here
Both cases however show the exact same user experience as far as I can tell. But the benefit of doing the background stop download is that the Locate the Nearest Stops operation happens much quicker.
The problem with the lower score for PWA is that chrome no longer automatically display the web app install banner. So I am in a situation where I need to make a choice and my current preference is for the background download to occur.
So the question is, is there a workaround which will allow me to have BOTH a high PWA score AND do the background download ?
Or is there any way of influencing how lighthouse scores PWAs, in my eyes anyway the background download resulting is lighthouse lengthening the time to interactive is not correct behavior ?

Related

Saving the input image from Face detection as a file? [Flutter + Google ML Kit Face Detection]

is it possible to save the processed image as a File?
Here is what I'm trying to do, our app have a KYC (Know your customer) and we implemented the
face detection to make the users do several poses. What I want is to save them as an image file and upload it on the database
Example Scenario:
App ask the user to smile > The user smiled > save the image.
Here is what I have right now:
Where the app checks if the user smiled
if (faces.isNotEmpty) {
if (inputImage.inputImageData?.size != null &&
inputImage.inputImageData?.imageRotation != null) {
if (faces[0].smilingProbability! > 0.85) {
await _getImg();
}
}
}
Then I call a Function to stop image stream then take a picture (this works but on some physical device it crashes) but if I dont stop the image stream then called the takePicture() right-away it just crashes all the time.
_getImg() async {
setState(() {
globalBusy = true;
});
await _controller.stopImageStream();
var img = await _controller.takePicture();
VerificationVarHandler.livelinesImgsPaths.add(img.path);
}
As you can see it's not the best way at least for me I think, so maybe I can use the
inputImage from the _processCameraImage() because it has a byte? then I can pass that bytes to a decoder and save it locally when I trigger a function?
Or maybe better yet there is more elegant way of achieving this?
You can check out this gfg article - https://www.geeksforgeeks.org/face-detection-in-flutter-using-firebase-ml-kit/
Learn flutter in easiest way - https://auth.geeksforgeeks.org/user/ms471841/articles

Flutter IOS beacon not able to scan with Region and UUID settings

I have this problem is that in flutter I notice there is not able to operate or use the traditional bluetooth as there is no any library supporting it. I have tested flutter_blue-master etc. So then I saw that it can behave as beacon. So I have used the codes below. For android I just set
Region(
identifier: 'com.example.myDeviceRegion',)); its able to work. So the same I set in IOS its not able to work? So what is best workaround for blueetooth in flutter? I am using this package flutter_beacon. For the beacon broadcasting I am using this package beacon_broadcast.
initScanBeacon() async {
await flutterBeacon.initializeScanning;
await checkAllRequirements();
if (!authorizationStatusOk ||
!locationServiceEnabled ||
!bluetoothEnabled) {
print('RETURNED, authorizationStatusOk=$authorizationStatusOk, '
'locationServiceEnabled=$locationServiceEnabled, '
'bluetoothEnabled=$bluetoothEnabled');
return;
}
/*final regions = <Region>[
Region(
identifier: 'com.example.myDeviceRegion',
),
];*/
final regions = <Region>[];
regions.add(Region(
identifier: 'com.example.myDeviceRegion',
minor: 100,
major: 1));
if (_streamRanging != null) {
if (_streamRanging.isPaused) {
_streamRanging.resume();
return;
}
}
_streamRanging =
flutterBeacon.monitoring(regions).listen((MonitoringResult result) {
print(result);
if (result != null && mounted) {
print("GOT RESTULT READY");
setState(() {
//_regionBeacons[result.region] = result.region;
_beacons.clear();
print("List value is json"+result.toJson.toString());
_regionBeacons.values.forEach((list) {
print("List value is");
_beacons.addAll(list);
print("after Beacon size now is "+_beacons.length.toString());
});
//_beacons.sort(_compareParameters);
print("Beacon size now is "+_beacons.length.toString());
});
}
});
}
A few things to check:
Make sure your Region definition has a proximityUUID value. I am surprised that it works even on Android without this. On iOS it certainly won't work at all -- iOS requires a beacon proximityUUID be specified up front in order to detect. The value you give for the prximityUUID must exactly match what your beacon is advertising or you won't see it.
Make sure you have gone through all the iOS setup steps here: https://pub.dev/packages/flutter_beacon
Be extra sure that you have granted location permission to your iOS app. You can go to Settings -> Your App Name to check if location permission is granted.
Make sure bluetooth is enabled in settings for the phone
Make sure location is enabled in settings for the phone
https://pub.dev/packages/flutter_beacon
There's an update on GitHub but was yet to push to pub.dev previously.
Do update to 0.5.0.
Always check pub.dev for updates. or github reported issues.

Ensure processing of a REST call in flutter app in background

I need to ensure that a certain HTTP request was send successfully. Therefore, I'm wondering if a simple way exists to move such a request into a background service task.
The background of my question is the following:
We're developing a survey application using flutter. Unfortunately, the app is intended to be used in an environment where no mobile internet connection can be guaranteed. Therefore, I’m not able to simply post the result of the survey one time but I have to retry it if it fails due to network problems. My current code looks like the following. The problem with my current solution is that it only works while the app is active all the time. If the user minimizes or closes the app, the data I want to upload is lost.
Therefore, I’m looking for a solution to wrap the upload process in a background service task so that it will be processed even when the user closes the app. I found several posts and plugins (namely https://medium.com/flutter-io/executing-dart-in-the-background-with-flutter-plugins-and-geofencing-2b3e40a1a124 and https://pub.dartlang.org/packages/background_fetch) but they don’t help in my particular use case. The first describes a way how the app could be notified when a certain event (namely the geofence occurred) and the second only works every 15 minutes and focuses a different scenario as well.
Does somebody knows a simple way how I can ensure that a request was processed even when there is a bad internet connection (or even none at the moment) while allowing the users to minimize or even close the app?
Future _processUploadQueue() async {
int retryCounter = 0;
Future.doWhile(() {
if(retryCounter == 10){
print('Abborted after 10 tries');
return false;
}
if (_request.uploaded) {
print('Upload ready');
return false;
}
if(! _request.uploaded) {
_networkService.sendRequest(request: _request.entry)
.then((id){
print(id);
setState(() {
_request.uploaded = true;
});
}).catchError((e) {
retryCounter++;
print(e);
});
}
// e ^ retryCounter, min 0 Sec, max 10 minutes
int waitTime = min(max(0, exp(retryCounter)).round(), 600);
print('Waiting $waitTime seconds till next try');
return new Future.delayed(new Duration(seconds: waitTime), () {
print('waited $waitTime seconds');
return true;
});
})
.then(print)
.catchError(print);
}
You can use the plugin shared_preferences to save each HTTP response to the device until the upload completes successfully. Like this:
requests: [
{
id: 8eh1gc,
request: "..."
},
...
],
Then whenever the app is launched, check if any requests are in the list, retry them, and delete them if they complete. You could also use the background_fetch to do this every 15 minutes.

Xamarin.Forms Taking picture with Plugin.Media not working

I'm using the Plugin.Media from #JamesMontemagno version 2.4.0-beta (which fixes picture orientation), it's working on Adroind 4.1.2 (Jelly Bean) and Marshmallow, but NOT on my Galaxy S5 Neo with Android version 5.1.1.
Basically when I take a picture it never returns back on the page from where I started the process; always returns back to the initial home page.
On devices where it works, when I take a picture, I see that first of all the application fires OnSleep, then after taking the picture fires OnResume.
On my device where is NOT working it fires OnSleep and after taking the picture doesn't fire OnResume, it fires the initialization page and then OnStart.
For this reason it doesn't open the page where I was when taking the picture.
What should I do to make sure it fires OnResume returning to the correct page and not OnStart which returns on initial fome page ?
In addition, when I take a picture it takes almost 30 seconds to get back to the code after awaiting TakePhotoAsync process, and it's too slow!
Following my code:
MyTapGestureRecognizerEditPicture.Tapped += async (sender, e) =>
{
//Display action sheet
String MyActionResult = await DisplayActionSheet(AppLocalization.UserInterface.EditImage,
AppLocalization.UserInterface.Cancel,
AppLocalization.UserInterface.Delete,
AppLocalization.UserInterface.TakePhoto,
AppLocalization.UserInterface.PickPhoto);
//Execute action result
if (MyActionResult == AppLocalization.UserInterface.TakePhoto)
{
//-----------------------------------------------------------------------------------------------------------------------------------------------
//Take photo
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert(AppLocalization.UserInterface.Alert, AppLocalization.UserInterface.NoCameraAvailable, AppLocalization.UserInterface.Ok);
}
else
{
var MyPhotoFile = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "MyApp",
Name = "MyAppProfile.jpg",
SaveToAlbum = true,
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Small
});
if (MyPhotoFile != null)
{
//Render image
MyProfilePicture.Source = ImageSource.FromFile(MyPhotoFile.Path);
//Save image on database
MemoryStream MyMemoryStream = new MemoryStream();
MyPhotoFile.GetStream().CopyTo(MyMemoryStream);
byte[] MyArrBytePicture = MyMemoryStream.ToArray();
await SaveProfilePicture(MyArrBytePicture);
MyPhotoFile.Dispose();
MyMemoryStream.Dispose();
}
}
}
if (MyActionResult == AppLocalization.UserInterface.PickPhoto)
{
//-----------------------------------------------------------------------------------------------------------------------------------------------
//Pick photo
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await DisplayAlert(AppLocalization.UserInterface.Alert, AppLocalization.UserInterface.PermissionNotGranted, AppLocalization.UserInterface.Ok);
}
else
{
var MyPhotoFile = await CrossMedia.Current.PickPhotoAsync();
if (MyPhotoFile != null)
{
//Render image
MyProfilePicture.Source = ImageSource.FromFile(MyPhotoFile.Path);
//Save image on database
MemoryStream MyMemoryStream = new MemoryStream();
MyPhotoFile.GetStream().CopyTo(MyMemoryStream);
byte[] MyArrBytePicture = MyMemoryStream.ToArray();
await SaveProfilePicture(MyArrBytePicture);
MyPhotoFile.Dispose();
MyMemoryStream.Dispose();
}
}
}
};
Please help!! We need to deploy this app but we cannot do it with this problem.
Thank you in advance!
It is perfectly normal to have the Android OS terminate and restart an Activity. As you are seeing, your app's Activity it will be automatically restarted when the camera app exits and the OS returns control to your app. The odds are it just needed more memory in order to take that photo with the Neo's 16MP camera, you can watch the logcat output to confirm that.
Restarted – It is possible for an activity that is anywhere from paused to stopped in the lifecycle to be removed from memory by Android. If the user navigates back to the activity it must be restarted, restored to its previously saved state, and then displayed to the user.
What to do:
So on the Xamarin.Forms OnStart lifecycle method you need to restore your application to a valid running state (initializing variables, preforming any bindings, etc...).
Plug code:
The Android platform code for the TakePhotoAsync method looks fine to me, but remember that the memory for that image that is passed back via the Task will be doubled as it is marshaled from the ART VM back the Mono VM. Calling GC.Collect() as soon as possible after the return will help (but your Activity is restarting anyway...)
public async Task<MediaFile> TakePhotoAsync(StoreCameraMediaOptions options)
{
~~~
var media = await TakeMediaAsync("image/*", MediaStore.ActionImageCapture, options);
In turn calls:
this.context.StartActivity(CreateMediaIntent(id, type, action, options));
Not much less you can really do within the Android OS to popup the Camera.
In addition, when I take a picture it takes almost 30 seconds to get back to the code after awaiting TakePhotoAsync process, and it's too slow!
Is that on your Neo? Or all devices?
I would call that very suspect (ie. a bug) as even flushing all the Java memory after the native Camera Intent/Activity and the restart time for your app's Activity should not take 30 seconds on a oct-core 1.6 GHz Cortex... but I do not have your device, app and code in front of me....

Same page appears while using ionic native transition plugin?

I am using ionic native transition plugin in my app. I am using slide up transition for pages.It works,but when state changes it shows the same page for a short period of time and then the other page (the page where I want to switch) appears. Here is the github link.I tried with different values for the default options, but it doesn't solve my problem. any help will be appreciated
I'm not sure if your issue is the same that I had (when transition to next/previous state begins the "new state" which it's supposed to transition to is shown in the "old view" before/during animation) but here is what I did. I found a solution which is to add a timeout to the state change in the stateGo() function in the ionic.native-transitions(.min).js which leads to it being run as the last function. The following code works on both iOS and Android devices.
function stateGo() {
var state = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0];
var stateParams = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var transitionOptions = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
var stateOptions = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
if (!state) {
$log.debug('[native transition] cannot change state without a state...');
return;
}
unregisterToStateChangeStartEvent();
transition(transitionOptions);
if (ionic.Platform.isIOS()) {
$timeout(function() {
$state.go(state, stateParams, stateOptions);
});
} else {
$state.go(state, stateParams, stateOptions);
}
}
I decided to add the check for an iOS device and run the timeout only in that case because it was only occurring in iOS devices and the timeout perhaps made Android devices flicker a little on the transition (I could be paranoid and this not really even occurring, or is due to large images on the content on my app).
Same fix probably also works in the case that you are using locationurl instead in which case you just set timeout to the "$location.url(url);" function.
Not sure if this would be the final solution for this problem but it works for now and hopefully the plugin will be fixed soon so this problem won't bother anyone else.
The same issue was on my side as well when using:
$scope.$on('$ionicView.enter', function(event, viewData) {
var transitionDirection = viewData.direction !== "back" ? "left": "right";
var options = {
"direction": transitionDirection,
"duration": 600,
"androiddelay": 75
};
window.plugins.nativepagetransitions.slide(
options,
function () {},
function () {}
);
});
However, when I changed the '$ionicView.enter' event to '$ionicView.beforeEnter', it solved the case for me. Not sure if that is a proper solution though.