How can I determine if the current platform is a native app or web in Capacitor? - capacitor

In Cordova you had immediate access to process.env.CORDOVA_PLATFORM is there something similar in Capacitor?
I'm looking to conditionally load some functions on startup and don’t want to block rendering waiting for async Device.getInfo to come back.
For example I want to determine immediately wether to import a script that make's native keyboard modifications, but I don't want to import this script if we are running on web
try {
const { Keyboard } = Plugins
Keyboard.setAccessoryBarVisible({ isVisible: true })
} catch (error) {
// Keyboard isn't available on web so we need to swallow the error
}
I'm using vue-cli

The answers so far are all correct, if you take a look into the Capacitors source code, there a few ways available, which can be used (but are undocumented for now):
Capacitor.getPlatform(); // -> 'web', 'ios' or 'android'
Capacitor.platform // -> 'web', 'ios' or 'android' (deprecated)
Capacitor.isNative // -> true or false
Be aware, that the method Capacitor.isPluginAvailable('PluginName'); only returns if the plugins is available or not (obviously) but important here, it does not tell you, if the method you want to execute after checking the availability is for your platform available.
The documentation of the Capacitor Plugins is not completed (yet).
Example (code), for the plugin StatusBar:
// Native StatusBar Plugin available
if (Capacitor.isPluginAvailable('StatusBar')) {
// Tint statusbar color
StatusBar.setBackgroundColor({
color: '#FF0000'
});
}
This would result in an error on iOS, since this method is not available there, on Android it works fine so far.
That means, that you need to implement a check of the Plugin and Platform combination by yourself (for now), may this will be improved in the future by Ionic / Capacitor itself.
Something like:
// Native StatusBar available
if (Capacitor.getPlatform() === 'android' && Capacitor.isPluginAvailable('StatusBar')) {
// Tint statusbar color
StatusBar.setBackgroundColor({
color: this.config.module.GYMY_MODAL_STATUSBAR_HEX_STRING
});
}
One more thing, you are not able to check, whether the method exists within this plugin (f. e. for the code above setBackgroundColor) as it is available, but throws an error (Error: not implemented) on a platform, which does not support it.
Hope I could help some of you guys.
Cheers
Unkn0wn0x

There is also the property Capacitor.isNative which you could use to determine whether the WebApp is running in Capacitor or in the Web.
https://github.com/ionic-team/capacitor/blob/master/core/src/definitions.ts
Update: In Capacitor V3 you can use Capacitor.isNativePlatform() for this.
https://capacitorjs.com/docs/v3/core-apis/web#isnativeplatform

As of Capacitor 3, you can use the following method to determine if it's running on a native device ("iOS" - "Android") or not ("web").
import { Capacitor } from '#capacitor/core';
if(Capacitor.isNativePlatform()) {
// Platform is mobile
} else {
// Platform is not mobile
}
Official documentation link. https://capacitorjs.com/docs/core-apis/web#isnativeplatform

Found it undocumented: Capacitor.platform
Capacitor.platform could be for example web ios android
Also if you wanted to know if you were running native before loading Capacitor, i.e you wanted to reduce bundle size by not including Capacitor on the web.
window.origin.includes('capacitor://')

You can now use Capacitor.isPluginAvailable('plugin name') to make this check, e.g., :
import { Capacitor, Plugins } from '#capacitor/core';
const { Keyboard } = Plugins;
...
const isAvailable = Capacitor.isPluginAvailable('Keyboard');
if (isAvailable) {
Keyboard.setAccessoryBarVisible({ isVisible: true })
}

You can see all of those on official doc here: https://capacitorjs.com/docs/basics/utilities#getplatform
if (Capacitor.getPlatform() === 'ios') {
// do something
}
if (Capacitor.isNative) {
// do something
}

I would say Device.getInfo() is the only reliable way of checking device's platform in capacitor based project.
Because the implementation of getPlatform(), Capacitor.platform is based on user agent of ui client. That means, if you opened your app on web and select developer tools then select mobile view, in this case it identify your platform as ios or android depending on which one you selected in dev tools instead of 'web'

Related

Flutter Windows: how can we add Header and footer in same code while we have code for mobile?

I have flutter 2.10 SDK but there is no documentation on native web Replacements. please anyone throw light on this issue.
What you need to do is to execute code based on the host platform.
First import the relevant headers
import 'dart:io' show Platform;
Using Platform APIs now you can detect the host platform and execute your codes for target platforms:
void myCode() {
if (Platform.isWindows) {
// do something specific for Windows here
} else {
// do something for other platforms
}
}

Flutter plugin for a file picker that works on mobile and desktop that doesn't require go-flutter?

This seems like an issue that won't last for long, but I'm looking for a final solution for opening up a native file picker on all platforms including Desktop without installing go-flutter.
Currently I'm using file_selector plugin by Flutter.dev and it's working for web and macOS (I have yet to test on windows/linux). When I try to run it on an iOS simulator, I get an error.
MissingPluginException(No implementation found for method openFile on channel plugins.flutter.io/file_selector)
I guess this is because it doesn't support iOS and maybe this plugin is just for desktop and web.
I also saw the file_picker plugin but it requires go-flutter to be installed on the desktop to get that to work. I'd rather have nice hot-reloads/builds directly in Android studio and not need go-flutter commands to run the desktop simulations.
Is there a one stop solution that basically combines these two things? I'm pretty new to Flutter, so maybe I'm missing a really easy way to use one or the other library depending on platform with some kind of conditional? It seems kind of messy to go that route, but it could work for now.
The other answer that I'm looking for is a good solution to using file_picker plugin for desktop in an easier way, such as how to use go-flutter seamlessly.
I ended up using a conditional to detect the Platform and will use file_picker for iOS/Android and then file_selector for web/desktop.
So far it's working well. I'll probably write a quick wrapper to abstract that out of the main code.
It seems like the easiest way to do this currently is to use a package like file_picker_desktop for Windows/Mac/Linux and file_picker on Android/iOS/Web. They seem to have similar APIs, so you can make a wrapper function on your app that calls the correct library.
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart' show kIsWeb;
if (Platform.isAndroid || Platform.isIOS)) {
// use file_picker plugin
FilePickerResult? result = await FilePicker.platform.pickFiles();
if(result != null) {
File file = File(result.files.single.path);
} else {
// User canceled the picker
}
} else if(kIsWeb) {
// use file_selector plugin
final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg',
'png']);
final file = await openFile(acceptedTypeGroups: [typeGroup]);
} else {
// use file_picker_desktop
try {
final result = await pickFiles(
allowMultiple: false,
);
if (result != null) {
File file = File(result.files.single.path);
} else {
// User canceled the picker
}
} catch (e) {
print(e);
}
}
The current latest version of the file_picker plugin (4.4.0) claims to work on all supported platforms, incl. desktop and Web.
I trie with Flutter 2.10.2 on macOS 12.2.1 and it works well. Also successfully tested on Win10.
final path = await FilePicker.platform.saveFile(
dialogTitle: 'Expor data',
fileName: '_${bloc.lot}_${bloc.serial}.dat',
lockParentWindow: true,
);
Setting lockParentWindow makes the file picker application modale, btw.

How to access the hardware layer when building a NativeScript plugin?

I'm trying to build a plugin to access the camera and I'm not sure how to access the hardware. When I import android, it says that there is no camera2 of undefined.
import { Common } from './CameraPlugin.common';
import { android } from 'tns-core-modules/application';
export class CameraPlugin extends Common {
constructor() {
super();
}
public takePicture() {
const cameraManager = new android.hardware.camera2.CameraManager();
cameraManager.openCamera();
}
}
NativeScript has native access to the Java/Kotlin (on Android) and ObjC/Swift (on iOS) devices with some minor limitations. (1)(2)
First you don't want/need to import "android" from anything; it is a valid global on all Android devices. So all you have to do is do android. (or java., or whatever namespace you need access too.) The import you did actually just hid the android global and replaced it with a different object which for sure doesn't have it.
One word of caution; unless you have installed the platform typescript typings, your editor will NOT know what android., android.hardware., etc are. When you go to actually run it; NativeScript will know what it is and use it just fine.
If you want your editor to know what it is, you need to install the platform typings:
npm i --save-dev tns-platform-declarations and you can read how to set them up here: https://github.com/NativeScript/NativeScript/tree/master/tns-platform-declarations
NativeScript documentation related to how the engine accesses the native code.
(1) - https://docs.nativescript.org/core-concepts/android-runtime/overview
(2) - https://docs.nativescript.org/core-concepts/ios-runtime/Overview

Provide REST API from Ionic App

is it possible to provide a REST API from an Ionic App?
I tried to install express, to receive REST calls, but no luck so far.
Background is, that I want to call from one Ionic2 app a method of another Ionic2 app.
I looked hours around but couldn't find a way to do such thing. I know this is not the common way, but it's necessary for my case, because it should replace push notifications in a quite dirty way (due to missing dev accounts and it's just for demonstration purpose)
Have you looked into the Ionic Native httpd plugin? This may provide what you are looking for with a few tweaks
Usage example straight from their docs:
import { Httpd, HttpdOptions } from '#ionic-native/httpd';
constructor(private httpd: Httpd) { }
...
let options: HttpdOptions = {
www_root: 'httpd_root', // relative path to app's www directory
port: 80,
localhost_only: false
};
this.httpd.startServer(options).subscribe((data) => {
console.log('Server is live');
});

How to cause a chrome app to update as soon as possible?

Deploying a chrome packaged app and publishing updates on the chrome web store allows users to automatically receive application updates. There are situations where you want to know if the running application is the most current or not, and updating it. E.G.:
Just keeping the user on the most recent version.
Detecting a mismatch between the application and server side APIs, and requiring the client side application to update to use new server side APIs.
Documentation for chrome.runtime.requestUpdateCheck() offers a status of "throttled", "no_update", "update_available", but doesn't indicate what to do if a newer version is required.
Install a listener for chrome.runtime.onUpdateAvailable, which fires when the new .crx file has been downloaded and the new version is ready to be installed. Then, call chrome.runtime.requestUpdateCheck:
chrome.runtime.onUpdateAvailable.addListener(function(details) {
console.log("updating to version " + details.version);
chrome.runtime.reload();
});
chrome.runtime.requestUpdateCheck(function(status) {
if (status == "update_available") {
console.log("update pending...");
} else if (status == "no_update") {
console.log("no update found");
} else if (status == "throttled") {
console.log("Oops, I'm asking too frequently - I need to back off.");
}
});
Depending on your application, when an update is detected you may want to use something like setTimeout and call chrome.runtime.restart() or chrome.runtime.restart() later
According to the Google Chrome documentation you need to have
chrome.runtime.onUpdateAvailable.addListener(function(details) {
chrome.runtime.reload(); // To restart the chrome App instantaneously
});
But this take time to reflect JS changes into the chrome because background.js loaded into the background and it needs to be unloaded and loaded again
To cop this situation you need to include
chrome.runtime.onInstalled.addListener(function(details) {
chrome.runtime.reload();
});
as wel.
onInstalled called whenever google extension installed first time (fresh installation), google extension updated or google chrome updated.