I'm looking for a way to execute code in Flutter when the app is in Debug mode. Is that possible in Flutter? I can't seem to find it anywhere in the documentation.
Something like this
If(app.inDebugMode) {
print("Print only in debug mode");
}
How can I check if the Flutter application is running in debug or release mode?
In later versions, you can use kDebugMode:
if (kDebugMode)
doSomething();
While asserts can technically be used to manually create an "is debug mode" variable, you should avoid that.
Instead, use the constant kReleaseMode from package:flutter/foundation.dart
The difference is all about tree shaking.
Tree shaking (aka the compiler removing unused code) depends on variables being constants.
The issue is, with asserts our isInReleaseMode boolean is not a constant. So when shipping our app, both the dev and release code are included.
On the other hand, kReleaseMode is a constant. Therefore the compiler is correctly able to remove unused code, and we can safely do:
if (kReleaseMode) {
} else {
// Will be tree-shaked on release builds.
}
Here is a simple solution to this:
import 'package:flutter/foundation.dart';
Then you can use kReleaseMode like
if(kReleaseMode){ // Is Release Mode??
print('release mode');
} else {
print('debug mode');
}
Please use Remi's answer with kReleaseMode and kDebugMode or Dart compilation won't be able to tree-shake your code.
This little snippet should do what you need:
bool get isInDebugMode {
bool inDebugMode = false;
assert(inDebugMode = true);
return inDebugMode;
}
If not, you can configure your IDE to launch a different main.dart in debug mode where you can set a Boolean.
kDebugMode
You can now use the kDebugMode constant.
if (kDebugMode) {
// Code here will only be included in debug mode.
// As kDebugMode is a constant, the tree shaker
// will remove the code entirely from compiled code.
} else {
}
This is preferable over !kReleaseMode as it also checks for profile mode, i.e., kDebugMode means not in release mode and not in profile mode.
kReleaseMode
If you just want to check for release mode and not for profile mode, you can use kReleaseMode instead:
if (kReleaseMode) {
// Code here will only be run in release mode.
// As kReleaseMode is a constant, the tree shaker
// will remove the code entirely from other builds.
} else {
}
kProfileMode
If you just want to check for profile mode and not for release mode, you can use kProfileMode instead:
if (kProfileMode) {
// Code here will only be run in release mode.
// As kProfileMode is a constant, the tree shaker
// will remove the code entirely from other builds.
} else {
}
While this works, using constants kReleaseMode or kDebugMode is preferable. See Rémi's answer below for a full explanation, which should probably be the accepted question.
The easiest way is to use assert as it only runs in debug mode.
Here's an example from Flutter's Navigator source code:
assert(() {
if (navigator == null && !nullOk) {
throw new FlutterError(
'Navigator operation requested with a context that does not include a Navigator.\n'
'The context used to push or pop routes from the Navigator must be that of a '
'widget that is a descendant of a Navigator widget.'
);
}
return true;
}());
Note in particular the () at the end of the call - assert can only operate on a Boolean, so just passing in a function doesn't work.
Not to be picky, but the foundation package includes a kDebugMode constant.
So:
import 'package:flutter/foundation.dart' as Foundation;
if(Foundation.kDebugMode) {
print("App in debug mode");
}
I believe the latest way to do this is:
const bool prod = const bool.fromEnvironment('dart.vm.product');
src
Just import this
import 'package:flutter/foundation.dart'
String bulid = kReleaseMode ? "Release" : "";
or
String bulid = kDebugMode ? "Debug" : "";
or
String bulid = kProfileMode ? "Profile" : "";
Or try this
if (kDebugMode) {
print("Debug");
} else if (kReleaseMode) {
print("Release");
} else if (kProfileMode) {
print("Profile");
}
Make a file named constants.dart. Add these variables in it:
const bool kReleaseMode = bool.fromEnvironment('dart.vm.product');
const bool kProfileMode = bool.fromEnvironment('dart.vm.profile');
const bool kDebugMode = !kReleaseMode && !kProfileMode;
printk(String string) {
if (kDebugMode) {
// ignore: avoid_print
print(string);
}
}
Then import this constant file in any other file and use it like this:
import 'package:package_name/constants.dart';
if(kDebugMode){
//Debug code
}else{
//Non-Debug code
}
printk("Debug Log");
I've created this useful class, based on other answers and inspired on Android usage.
If anything changes on "Foundation" package, it would not be necessary to change the entire application, it would be necessary to change only this class.
import 'package:flutter/foundation.dart' as Foundation;
abstract class Build {
static const bool isDebugMode = Foundation.kDebugMode;
static const bool isReleaseMode = Foundation.kReleaseMode;
static const bool isWeb = Foundation.kIsWeb;
static const bool isProfileMode = Foundation.kProfileMode;
}
Extracted from Dart Documentation:
When exactly do assertions work? That depends on the tools and
framework you’re using:
Flutter enables assertions in debug mode.
Development-only tools such as dartdevc typically enable assertions by default.
Some tools, such as dart and dart2js, support assertions through a command-line flag: --enable-asserts.
In production code, assertions are ignored, and the arguments to
assert aren’t evaluated.
Related
I need to run the extension command right after the installation. There is an event like onStartupFinished, but the problem is, it will run every time the vscode starts.
How to do it? does vsocde have any way to do it?
You can use a version field in the global context state. You get the context in your activation method.
export const activate = (context: ExtensionContext): void => {
const myExtension = extensions.getExtension("<my-extension-id>");
const currentVersion = myExtension!.packageJSON.version ?? "1.0.0";
const lastVersion = context.globalState.get("MyExtensionVersion");
if (currentVersion !== lastVersion) {
void context.globalState.update("MyExtensionVersion", currentVersion);
// Do one time setup here.
}
}
Don't forget to set onStartupFinished in activationEvents.
I try to use the same code for both web and android. Where the code differs I switch between widgets based on a global variable.
Is the performance worse when using a non constant / non final variable when switching between widgets? I'm thinking, because the variable is not final or constant and can be changed at any point, Flutter will not be able to optimise the code. Is that true? If inefficient, how do I make my code efficient?
eg.
I have two main files and set my AppType enum in each
[appType.dart]
AppType appType; //can't think of how to make this constant or final
[android_main.dart]
void main() {
appType = AppType.and;
[web_main.dart]
void main() {
appType = AppType.and;
In my widgets I switch where I need a widget specific for the web or android
if(appType == AppType.web)
return MyWidgetWeb();
else
return MyWeigetAnd();
Yes, a constant is more efficient, mainly because of tree-shaking.
Assume that you have the following types:
enum AppType {
mobile,
web,
}
class Mobile {}
class Web {}
Then when you write:
const type = AppType.web;
void main() {
if (type == AppType.web) {
print(Web());
}
else if (type == AppType.mobile) {
print(Mobile());
}
}
Then when compiling the code, the compiler knows that the if block will always be reached, and the else if never will.
As such:
the conditions are removed. When compiled, the code will be:
const type = AppType.web;
void main() {
// no `if` performed
print(Web());
}
Mobile will not be bundled in the executable, so you have a lighter application.
To fully benefit from this behavior, you can use Dart "defines", using int/bool/String.fromEnvironment, which allows you to define constants that behave differently depending on some external build parameters.
The way such constant would look like is:
const isWeb = bool.fromEnvironment('isWeb', defaultValue: false);
Which you can then control using arguments on flutter run and flutter build commands:
flutter build <whatever> --dart-define=isWeb=true
Is it possible to show users of your extension or color theme notifications in Visual Studio Code? For someone who has my color theme or extension installed and is getting updates, I would like to possibly show this person a notification after they update the extension (That could be on launch of VSCode, or right after they go into the market to update & reload the extension and client themselves.)
For example: I think it would be beneficial to me and not invasive if they saw a notification after updating the extension saying "Feedback? Suggestions? Fixes?..on the theme?" OR notifying them of something changed in the theme that may not be favorable. So they can "opt out" of that change if they want (Like an extra set of borders around something or the color change of something.)
Obviously people with all notifications off would not be affected, but I thought an occasional notification after a rare update wouldn't be too bad. I have not been able to find info on if this is possible, and if it was, how to do it. Any info on this is appreciated. And if it is possible, those reading this, whether you've done it or not, would you recommend showing a notification to your theme users in that way?
Thanks :)
Show a notification on bottom-right corner, whenever your extension is updated. You can also control to show it only for major/minor releases.
That's how it looks:
Add below code to extension.ts:
import { window, ExtensionContext, extensions, env, Uri } from "vscode";
const extensionId = "jerrygoyal.shortcut-menu-bar";
// this method is called when your extension is activated
export function activate(context: ExtensionContext) {
showWhatsNew(context); // show notification in case of a major release i.e. 1.0.0 -> 2.0.0
}
// https://stackoverflow.com/a/66303259/3073272
function isMajorUpdate(previousVersion: string, currentVersion: string) {
// rain-check for malformed string
if (previousVersion.indexOf(".") === -1) {
return true;
}
//returns int array [1,1,1] i.e. [major,minor,patch]
var previousVerArr = previousVersion.split(".").map(Number);
var currentVerArr = currentVersion.split(".").map(Number);
if (currentVerArr[0] > previousVerArr[0]) {
return true;
} else {
return false;
}
}
async function showWhatsNew(context: ExtensionContext) {
const previousVersion = context.globalState.get<string>(extensionId);
const currentVersion = extensions.getExtension(extensionId)!.packageJSON
.version;
// store latest version
context.globalState.update(extensionId, currentVersion);
if (
previousVersion === undefined ||
isMajorUpdate(previousVersion, currentVersion)
) {
// show whats new notificatin:
const actions = [{ title: "See how" }];
const result = await window.showInformationMessage(
`Shortcut Menubar v${currentVersion} — Add your own buttons!`,
...actions
);
if (result !== null) {
if (result === actions[0]) {
await env.openExternal(
Uri.parse(
"https://github.com/GorvGoyl/Shortcut-Menu-Bar-VSCode-Extension#create-buttons-with-custom-commands"
)
);
}
}
}
}
You can see this implementation in my VSCode extension repo Shortcut Menu Bar
I think you can register the version during activation event and check for it on each activation. Then you can do whatever you want. For instance GitLens is migrating settings https://github.com/eamodio/vscode-gitlens/blob/master/src/extension.ts#L52 and i'm pretty sure I remember that they were opening a notification (but i have not found immediately in the code)
regards,
I am investigating using Ionic 4/ Capacitor to target Windows via the Electron option, for an application where I want to use SQLite.
Using the Ionic Native SQLite plugin, which wraps this Cordova plugin, out of the box, as far as I can see, the Windows support is for UWP, and not Desktop, which runs using Electron in Ionic Capacitor wrapper.
My plan, was to see if I could use Electron SQLite package, and then call this from my Ionic application by making a wrapper class for the Ionic native similar to what I used to get browser support by following this tutoral
If I can call the Electron code from my Ionic app, then I can't see why this wouldn't work.
So, my question here is, can I call code (I will add functions to use the SQlite) I add to the hosting Electron application from within the Ionic (web) code? And if so, how?
Thanks in advance for any help
[UPDATE1]
Tried the following...
From an Ionic page, I have a button click handler where I raise an event..
export class HomePage {
public devtools() : void {
let emit = new EventEmitter(true);
emit.emit('myEvent');
var evt = new CustomEvent('myEvent');
window.dispatchEvent(evt);
}
Then within the Electron projects index.js, I tried..
mainWindow.webContents.on('myEvent', () => {
mainWindow.openDevTools();
});
const ipc = require('electron').ipcMain
ipc.on('myEvent', (ev, arg) => {
mainWindow.openDevTools();
});
But neither worked.
I should mention I know very little about Electron. This is my first exposure to it (via Capacitor)
In case someone is interested, this is how I solved this.
Im am using Ionic 4 / Capacitor + Vue 3.
In my entry file (app.ts) I have declared a global interface called Window as follows:
// app.ts
declare global { interface Window { require: any; } }
Then, I have written the following class:
// electron.ts
import { isPlatform } from '#ionic/core';
export class Electron
{
public static isElectron = isPlatform(window, 'electron');
public static getElectron()
{
if (this.isElectron)
{
return window.require('electron');
}
else
{
return null;
}
}
public static getIpcRenderer()
{
if (this.isElectron)
{
return window.require('electron').ipcRenderer;
}
else
{
return null;
}
}
public static getOs()
{
if (this.isElectron)
{
return window.require('os');
}
else
{
return null;
}
}
}
And I use it like this:
//electronabout.ts
import { IAbout } from './iabout';
import { Plugins } from '#capacitor/core';
import { Electron } from '../utils/electron';
export class ElectronAbout implements IAbout
{
constructor() { }
public async getDeviceInfo()
{
let os = Electron.getOs();
let devInfo =
{
arch: os.arch(),
platform: os.platform(),
type: os.type(),
userInfo: os.userInfo()
};
return devInfo;
}
public async showDeviceInfo()
{
const devInfo = await this.getDeviceInfo();
await Plugins.Modals.alert({ title: 'Info from Electron', message: JSON.stringify(devInfo) });
}
}
This is working but, of course, I still need to refactor the Electron class (electron.ts). Probably using the singleton pattern is a better idea.
I hope this helps.
Update
You can communicate from the render process with your main process (index.js) like this:
//somefile.ts
if (Electron.isElectron)
{
let ipc = Electron.getIpcRenderer();
ipc.once('hide-menu-button', (event) => { this.isMenuButtonVisible = false; });
}
//index.js
let newWindow = new BrowserWindow(windowOptions);
newWindow.loadURL(`file://${__dirname}/app/index.html`);
newWindow.webContents.on('dom-ready', () => {
newWindow.webContents.send('hide-menu-button');
newWindow.show();
});
I dug into this yesterday and have an example for you using angular(this should apply to ionic too).
in your service declare require so we can use it
//Below your imports
declare function require(name:string);
Then in whatever function you want to use it in:
// Require the ipcRenderer so we can emit to the ipc to call a function
// Use ts-ignore or else angular wont compile
// #ts-ignore
const ipc = window.require('electron').ipcRenderer;
// Send a message to the ipc
// #ts-ignore
ipc.send('test', 'google');
Then in the created index.js within the electron folder
// Listening for the emitted event
ipc.addListener('test', (ev, arg) => {
// console.log('ev', ev);
console.log('arg', arg);
});
Its probably not the correct way to access it but its the best way i could find. From my understanding the ipcRenderer is used for when you have multiple browsers talking to each other within electron. so in our situation it enables our web layer to communicate with the electron stuff
I am running with multiCapabilities, and would like to know if it is possible to know what capability is currently used, both in the onPrepare function and/or the testcase itself.
The use case is that I am planning to run my tests both on chrome and on android. For Chrome the window should be resized to required dimensions, however running the same code on selendroid gives an exception because the method is not implemented (also resizing a window on a device does not really make sense):
So, the idea was to somehow wrap the offending code in a simple check like so:
if(browser != 'android')
browser.driver.manage().window().setSize(480, 800);
There are also other use cases, but that's the most important one for now.
I do stuff like that within the onPrepare section, e.g.
// Return if current browser is IE, optionally specifying if it is a particular IE version
browser.isInternetExplorer = function(ver) {
var browserName, version, ie;
return browser.getCapabilities().then(function(s) {
browserName = s.caps_.browserName;
version = s.caps_.version;
ie = /i.*explore/.test(browserName);
if (ver == null) {
return ie;
} else {
return ie && ver.toString() === version;
}
});
};
Then, later on, i use it like this:
if (browser.isInternetExplorer()) {...}
For android this should work:
browser.isAndroid = function(ver) {
var browserName, version;
return browser.getCapabilities().then(function(s) {
browserName = s.caps_.browserName;
version = s.caps_.version;
return /droid/.test(browserName);
});
};