I'd like to trigger some code to happen after the user installs a version of our Xamarin Forms application. But I need it for every version install, not just the first installation, so setting a property flag won't work.
I have a solution that tracks application version numbers and can trigger it off that, but I was hoping there was an framework event or something that was more elegant.
You can use Xamarin Essentials' Version Tracking
From there you can check when either the first time the current build is run, or the first time the current version is run:
// First time launching current version
var firstLaunchCurrent = VersionTracking.IsFirstLaunchForCurrentVersion;
// First time launching current build
var firstLaunchBuild = VersionTracking.IsFirstLaunchForCurrentBuild;
Related
I am using Xamarin.Firebase.iOS.DynamicLinks 2.3.1.1 for dynamic links, Earlier it was working fine but recently it is not working. While trying to extract the short link, long link getting null. Is anyone knows why it is not working?
I have updated to the latest version (4.0.1) and its working fine. It not working any of the previous version of NuGet packages.
To answer your question. The Dynamic links are not working either on Firebase's end who choose to discontinue their old library or due to the newest IOS update 13.3. I say this because my app that is in production had its links working fine then they suddenly stopped working.
My current solution was to update Xamarin.Firebase.iOS.DynamicLinks to (4.0.1) and I was able to once again process the long url with its parameters.
A few things to note if you have other libraries such as Firestore, Analytics, Notifications etc.
You might run into linker failed exceptions. They occur because
Xamarin.Firebase.iOS.DynamicLinks (3.0.2.1) and prior depended on
Xamarin.Firebase.iOS.Core (>= 5.1.3) and the working
Xamarin.Firebase.iOS.DynamicLinks (4.0.1.1) references
Xamarin.Firebase.iOS.Core (>= 6.1.0.1) Somehow they reference methods that are no longer available.
The linking failed is fixed by checking each of your nuGets and manually installing their respective nuGets that reference ...iOS.Core (>= 6.1.0.1) : For example:
if you use Xamarin.Firebase.iOS.Storage (2.0.0) manually install
Xamarin.Firebase.iOS.Storage (3.4.0.1) because
Xamarin.Firebase.iOS.Storage (2.0.0) references
Xamarin.Firebase.iOS.Storage (>= 3.0.2) which in turn references:
Xamarin.Firebase.iOS.Core (>= 5.1.3) and it will cause native linking failed
And lastly, in my case Xamarin.Firebase.iOS.DynamicLinks (4.0.1.1) will make your method for generating ShortLinks, stop working too:
In Xamarin.Firebase.iOS.DynamicLinks (3.0.2.1) you would build your
DynamicLinkComponents with:
var shareLink = DynamicLinkComponents.FromLink(linkParameters,
"YOUR_DOMAIN.page.link");
Xamarin.Firebase.iOS.DynamicLinks (4.0.1.1) recomends you use
DynamicLinkComponents.Create(YOURlinkParameters, "YOUR_DOMAIN.page.link");
but it would return a null DynamicLinkComponents so i fixed by doing:
var shareLink = new DynamicLinkComponents();
shareLink.Link = YOURlinkParameters;
shareLink.Domain = "https://YOUR_DOMAIN.page.link";
I spent a week trying to troubleshoot this error and really hope others are able to see this and save you valuable time.
A work around to get Xamarin.Firebase.iOS.DynamicLinks 3.0.2.1 working (should work on 2.3.1.1 as well) is to have the IOS device open the link in the browser which will then redirect them back to the app.
The flow is Dynamic link > App [short link] > Browser > App with [long link].
Dynamic links are formatted "domain.page.link/ShortSequence" and long links parameters have "domain.page.link/?". You can look for the '?' to decide weather to process url or to redirect user as follows:
public override bool ContinueUserActivity(UIApplication application,
NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
if (userActivity.ActivityType == NSUserActivityType.BrowsingWeb)
{
var sharedLink = userActivity.WebPageUrl;
if (!sharedLink.ToString().Contains("domain.page.link/?")){
await Launcher.OpenAsync(new Uri(sharedLink.ToString()));
return;
}
var handled = DynamicLinks.SharedInstance.FromUniversalLinkUrl(sharedLink);
//Process your DynamicLink parameters
}
return true;
}
I need to distribute some settings based on the app version e.g. if app version equals "4.0.1" then a else b. I found the possibility to define a condition named "version" but the documentation says it is bound to the package name of the app and not the version or version code.
see here https://firebase.google.com/docs/remote-config/parameters
I tried it though specifying the app version through a "version" condition but it does not work. Any ideas on this would be much appreciated.
The main problem is that Remote config's "Version" is the build number and not the actual version number.
The way I found around this is you can add a "User Property" in Firebase like "app_version". Then when the app launches add the following code:
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
Analytics.setUserProperty(version, forName: "app_version")
You can then use this User Property in Remote Config as a condition and voila you can base some Remote Config value of of the version number. Note this will require the use of Firebase Analytics as well.
Creating a condition, which targets an app version via regular expression appears to be the only solution in this case.
For my app I use the following configuration:
Here, users who have versions 1.8.* and below receive an alternate version of a backend configuration parameter.
If you need to target only a specific version of the app, then a regular expression is not really necessary, so the approach that you took should work.
Alternatively, you can have far more control if you create a user audience based on app version, and then target the audience.
First up, I'm fairly new to .NET and C# and this is a project to learn C# and CEF at the same time.
I have followed a number of tutorials from the net as well as looking into the CefSharp examples to create a WinForms application.
I have installed CefSharp.WinForms 53.0.1 from NuGet, and my project is using Any CPU (CefSharp 51+ has Any CPU support).
To achieve this I largely followed the tutorial from Ourcode (http://ourcodeworld.com/articles/read/173/how-to-use-cefsharp-chromium-embedded-framework-csharp-in-a-winforms-application). I made the changes for Any CPU as suggested and included the basic code to load google.
Everything builds fine, but when the form displays there's no browser shown, just a blank form.
If I set the target to x64 or x86, then the browser displays as expected.
I notice in the Ourcode comments that user Edek Halon has had the same issue, but no solution seems to be provided. Edek, has the same setup as me, so I wonder if this is an issue in 53.0.1? Potentialy Joey De Vries in the comments has the same issue.
The addition of support for Any CPU in CefSharp is covered in this GitHub issue : https://github.com/cefsharp/CefSharp/issues/1714
There is a troubleshooting page for CefSharp (https://github.com/cefsharp/CefSharp/wiki/Trouble-Shooting) and it seems a bit contradictory. Under General Troubleshooting
1) Platform Target You must select either x86 or x64 when using the NuGet packages. If you select AnyCPU the NuGet magic won't work currently.
Does CefSharp need to be built from source for Any CPU to work?
Just if anyone is having difficulties with this, follow the Github Tutorial at the following link : https://github.com/cefsharp/CefSharp/issues/1714
Basically the code should be as follows (Winforms Example):
CefSharpSettings.SubprocessExitIfParentProcessClosed = true;
Cef.EnableHighDPISupport();
CefSettings settings = new CefSettings
{
CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache"), //By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
BrowserSubprocessPath = #"x86\CefSharp.BrowserSubprocess.exe"
};
Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null); // Initialize cef with the provided settings
chromeBrowser = new ChromiumWebBrowser("http://ourcodeworld.com"); // Create a browser component
this.Controls.Add(chromeBrowser); // Add it to the form and fill it to the form window.
chromeBrowser.Dock = DockStyle.Fill;
I'm currently using the Qt Installer Framework and managed to set up an online repository. What I want to know is:
Does the Framework provide some kind of "auto-update" mechanism, e.g. a plugin/service that checks for updates every time the program/system starts?
Check for updates would be enough, since the installation itself can be done using the maintanance tool.
All I could find about this topic was this small sentence:
End users can use the maintenance tool to install additional components from the server after the initial installation, as well as to receive automatic updates to content as soon as the updates are published on the server.
from here: http://doc.qt.io/qtinstallerframework/ifw-overview.html#choosing-installer-type
Thanks for your help!
Edit: Suggestion
Based on this question's accepted answere I created a small library to automatically check for updates using the installer framework - https://github.com/Skycoder42/QtAutoUpdater
What I do, is run the maintenance tool using QProcess, and then check the output. It has a mode where it doesn't run the GUI but only outputs update information if available.
Note that I set the working directory to the application's path when the applications starts, so I can just run maintenancetool.
QProcess process;
process.start("maintenancetool --checkupdates");
// Wait until the update tool is finished
process.waitForFinished();
if(process.error() != QProcess::UnknownError)
{
qDebug() << "Error checking for updates";
return false;
}
// Read the output
QByteArray data = process.readAllStandardOutput();
// No output means no updates available
// Note that the exit code will also be 1, but we don't use that
// Also note that we should parse the output instead of just checking if it is empty if we want specific update info
if(data.isEmpty())
{
qDebug() << "No updates available";
return false;
}
// Call the maintenance tool binary
// Note: we start it detached because this application need to close for the update
QStringList args("--updater");
bool success = QProcess::startDetached("maintenancetool", args);
// Close the application
qApp->closeAllWindows();
In the latest Qt Installer Framework 4.1 --checkupdates returns nothing, use ch or check-updates instead.
Commands:
in, install - install default or selected packages - <pkg ...>
ch, check-updates - show available updates information on maintenance tool
up, update - update all or selected packages - <pkg ...>
rm, remove - uninstall packages and their child components - <pkg ...>
li, list - list currently installed packages - <regexp>
se, search - search available packages - <regexp>
co, create-offline - create offline installer from selected packages - <pkg ...>
pr, purge - uninstall all packages and remove entire program directory
I just found a pretty nice implementation on GitHub:
https://github.com/ioriayane/TheArtOfQt2/blob/master/src/HelloWorld/maintenancetool.cpp
It takes care of handling Windows, MacOS and Linux. + It is written to use in QML / Qt Quick bindings (+ example).
It has some Japanese comments, but is Apache 2.0 licensed, so freely to use (following Apache 2.0 requirement).
There's a section in the guide about how to do it, but they call it promoting updates rather than auto updates, IFW Updates on doc.qt.io.
we are developing an Adobe AIR app using Flex4. We are facing lot of bugs that didn't show up when we run the application inside Flash Builder (both debug mode and run mode), but when we install the app and run it, the app shows a different behaviour. Any idea ? what does it change between running the installed application in the builder and outside ?
Thanks a lot
Ok i've founded the problem using MonsterDebugger in the application running stand alone. The problem was the File.browseForDirectory(). I'm creating the File object, registering the event listener and then calling File.browseForDirectory() and that generate an exception. I switched the order, First creating a new file, then calling File.browseForDirectory() and at last register an event handler and works great.
My guess is that inside the debugger version and inside Flash Builder it takes just few more millisec and the File object is ready when i register the eventlistener but in the stand alone application AS3 code for event listener registration is executed before the File object initialization.