A Javascript engine to use with flutter. It uses quickjs on Android and JavascriptCore on IOS

Related tags

Desktop flutter_js
Overview

Flutter JS plugin

A Javascript engine to use with flutter. Now it is using QuickJS on Android through Dart ffi and JavascriptCore on IOS also through dart-ffi. The Javascript runtimes runs synchronously through the dart ffi. So now you can run javascript code as a native citzen inside yours Flutter Mobile Apps (Android, IOS, Windows, Linux and MacOS are all supported).

In the previous versions we only get the result of evaluated expressions as String.

BUT NOW we can do more with flutter_js, like run xhr and fetch http calls through Dart http library. We are supporting Promises as well.

With flutter_js Flutter applications can take advantage of great javascript libraries such as ajv (json schema validation), moment (DateTime parser and operations) running natively (no PlatformChannels needed) on mobile devices, both Android and iOS.

On IOS this library relies on the native JavascriptCore provided by iOS SDK. In Android it uses the amazing and small Javascript Engine QuickJS https://bellard.org/quickjs/ (A spetacular work of the Fabrice Bellard and Charlie Gordon).

On Android you could use JavascriptCore as well You just need add an Android dependency implementation "com.github.fast-development.android-js-runtimes:fastdev-jsruntimes-jsc:0.1.3" and pass forceJavascriptCoreOnAndroid: true to the function getJavascriptRuntime.

On MacOS the JavascriptCore, provided by the OSX is used. In Windows and Linux the engine used is the QuickJS. In the 0.4.0 version we borrowed the dart ffi source code from the flutter_qjs lib. flutter_qjs is a amazing package and they made a excelent work in build a good ffi bridge between Dart and JS, also doing the quickjs source code changes to allow it to run on WIndows. But, flutter_js take the approach to use JavascriptCore on IOS (mainly) to avoid refusals on the Apple Store, which state that Apps may contain or run code that is not embedded in the binary (e.g. HTML5-based games, bots, etc.), as long as code distribution isn’t the main purpose of the app. It also says your app must use WebKit and JavaScript Core to run third-party software and should not attempt to extend or expose native platform APIs to third-party software; Reference: https://developer.apple.com/app-store/review/guidelines/ [ Session 4.7]. So, we avoid to use quickjs in IOS apps, so flutter_js provides an abstraction called JavascriptRuntime which runs using JavascriptCore on Apple devices and Desktop and QuickJS in Android, Windows and Linux.

FLutterJS allows to use Javascript to execute validations logic of TextFormField, also we can execute rule engines or redux logic shared from our web applications. The opportunities are huge.

The project is open source under MIT license.

The bindings for use to communicate with JavascriptCore through dart:ffi we borrowed it from the package flutter_jscore.

Flutter JS provided the implementation to the QuickJS dart ffi bindings and also constructed a wrapper API to Dart which provides a unified API to evaluate javascript and communicate between Dart and Javascript through QuickJS and Javascript Core in a unified way.

This library also allows to call xhr and fetch on Javascript through Dart Http calls. We also provide the implementation which allows to evaluate promises.

Flutter JS on Mobile

Flutter JS on Desktop

Features:

Instalation

dependencies:
  flutter_js: 0.1.0+0

iOS

Since flutter_js uses the native JavascriptCore, no action is needed.

Android

Change the minimum Android sdk version to 21 (or higher) in your android/app/build.gradle file.

minSdkVersion 21

Release Deploy

Android

Setup of proguard to release builds: setup your android/app/proguard-rules.pro file with the content bellow.

Remember to merge with another configurations needed for others plugins your app uses.

#Flutter Wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.**  { *; }
-keep class io.flutter.util.**  { *; }
-keep class io.flutter.view.**  { *; }
-keep class io.flutter.**  { *; }
-keep class io.flutter.plugins.**  { *; }
-keep class de.prosiebensat1digital.** { *; }

Also add these lines to your android -> buildTypes -> release section of android/app/build.gradle file:

 minifyEnabled true
  useProguard true

  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

Examples

Here is a small flutter app showing how to evaluate javascript code inside a flutter app

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_js/flutter_js.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _jsResult = '';
  JavascriptRuntime flutterJs;
  @override
  void initState() {
    super.initState();
    
    flutterJs = getJavascriptRuntime();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('FlutterJS Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('JS Evaluate Result: $_jsResult\n'),
              SizedBox(height: 20,),
              Padding(padding: EdgeInsets.all(10), child: Text('Click on the big JS Yellow Button to evaluate the expression bellow using the flutter_js plugin'),),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text("Math.trunc(Math.random() * 100).toString();", style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic, fontWeight: FontWeight.bold),),
              )
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          backgroundColor: Colors.transparent, 
          child: Image.asset('assets/js.ico'),
          onPressed: () async {
            try {
              JsEvalResult jsResult = flutterJs.evaluate(
                  "Math.trunc(Math.random() * 100).toString();");
              setState(() {
                _jsResult = jsResult.stringResult;
              });
            } on PlatformException catch (e) {
              print('ERRO: ${e.details}');
            }
          },
        ),
      ),
    );
  }
}

How to call dart from Javascript

You can add a channel on JavascriptRuntime objects to receive calls from the Javascript engine:

In the dart side:

javascriptRuntime.onMessage('someChannelName', (dynamic args) {
     print(args);
});

Now, if your javascript code calls sendMessage('someChannelName', JSON.stringify([1,2,3]); the above dart function provided as the second argument will be called with a List containing 1, 2, 3 as it elements.

Alternatives (and also why we think our library is better)

There were another packages which provides alternatives to evaluate javascript in flutter projects:

https://pub.dev/packages/flutter_liquidcore

Good, is based on https://github.com/LiquidPlayer/LiquidCore

It is based on V8 engine so the exectuable library is huge (20Mb). So the final app will be huge too.

https://pub.dev/packages/interactive_webview

Allows to evaluate javascript in a hidden webview. Does not add weight to size of the app, but a webview means a entire browser is in memory just to evaluate javascript code. So we think an embeddable engine is a way better solution.

https://pub.dev/packages/jsengine

Based on jerryscript which is slower than quickjs. The jsengine package does not have implementation to iOS.

https://pub.dev/packages/flutter_jscore

Uses Javascript Core in Android and IOS. We got the JavascriptCore bindings from this amazing package. But, by default we provides QuickJS as the javascript runtime on Android because it provides a smaller footprint. Also our library adds support to ConsoleLog, SetTimeout, Xhr, Fetch and Promises to be used in the scripts evaluation and allows your Flutter app to provide dartFunctions as channels through onMessage function to be called inside your javascript code.

https://pub.dev/packages/flutter_qjs

Amazing package which does implement the javascript engine using quickjs through Dart ffi. The only difference is it uses quickjs also on IOS devices, which we understand would be problematic to pass Apple Store Review process. In the flutter_js 0.4.0 version, which we added support to Desktop and also improved the Dart/Js integration, we borrowed the C function bindings and Dart/JS conversions and integrations from the flutter_qjs source code. We just adapted it to support xhr, fetch and to keep the same interface provided on flutter_js through the class JavascriptRuntime.

Small Apk size

A hello world flutter app, according flutter docs has 4.2 Mb or 4.6 Mb in size.

https://flutter.dev/docs/perf/app-size#android

Bellow you can see the apk sizes of the example app generated with flutter_js:

|master ✓| → flutter build apk --split-per-abi

✓ Built build/app/outputs/apk/release/app-armeabi-v7a-release.apk (5.4MB).
✓ Built build/app/outputs/apk/release/app-arm64-v8a-release.apk (5.9MB).
✓ Built build/app/outputs/apk/release/app-x86_64-release.apk (6.1MB).

Ajv

We just added an example of use of the amazing js library Ajv which allow to bring state of the art json schema validation features to the Flutter world. We can see the Ajv examples here: https://github.com/abner/flutter_js/blob/master/example/lib/ajv_example.dart

See bellow the screens we added to the example app:

IOS

ios_form

ios_ajv_result

Android

android_form

android_ajv_result

MACOS

  • To solve Command Line Tool - Error - xcrun: error: unable to find utility “xcodebuild”, not a developer tool or in PATH

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

In Catalina with XCode 12 i needed to install ruby 2.7.2 in order to install cocoapods (Also needed to Flutter on IOS). So i installed brewand after rbenv.

To enable http calls, add this to your files:

  • DebugProfile.entitlements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.cs.allow-jit</key>
	<true/>
	<key>com.apple.security.network.client</key>
	<true/>
	<key>com.apple.security.network.server</key>
	<true/>
</dict>
</plist>
  • Release.entitlements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.network.client</key>
	<true/>
	<key>com.apple.security.network.server</key>
	<true/>
</dict>
</plist>

Windows and Linux

The C wrapper library is hosted on this github repository: https://github.com/abner/quickjs-c-bridge

We just separated the code to allow build it and in this repository we have only the released shared library, so each application using the flutter_js does not need to keep recompiling it all the time

QuickJs Android shared libraries

The library wrapper, both QuickJS and JavascriptCore, are also compiled in a separated repository: https://github.com/fast-development/android-js-runtimes

With the library being compiled and published to jitpack, applications using the wrappers, through flutter_js does not need to compile the shared library using Android NDK.

Unit Testing javascript evaluation

We can unit test evaluation of expressions on flutter_js using the desktop platforms (windows, linux and macos).

For Windows and Linux you need to build your app Desktop executable first: flutter build -d windows or flutter build -d linux.

On Windows, after build your application for the first time, at least, add the path build\windows\runner\Debug (the absolute path) to your environment path.

In powershell, just run $env:path += ";${pwd}\build\windows\runner\Debug". Now you can run the test in the command line session where you added the \build\windows\runner\Debug into the path.

For Linux you need to exports an environment variable called LIBQUICKJSC_TEST_PATH pointing to build/linux/debug/bundle/lib/libquickjs_c_bridge_plugin.so. eg: export LIBQUICKJSC_TEST_PATH="$PWD/build/linux/debug/bundle/lib/libquickjs_c_bridge_plugin.so"

To run the test integrated Visual Studio Code, you will need to setup a launcher to the .vscode/launch.json file, so you can fill-in the build folder into the PATH on Windows and the LIBQUICKJSC_TEST_PATH for linux:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "test-with-flutterjs",
            "type": "dart",
            "program": "test/flutter_js_test.dart",
            "windows": {
                "env": {
                    "PATH": "${env:Path};${workspaceFolder}\\example\\build\\windows\\runner\\Debug"
                }
            },
            "linux": {
                "env": {
                    "LIBQUICKJSC_TEST_PATH": "${workspaceFolder}/example/build/linux/debug/bundle/lib/libquickjs_c_bridge_plugin.so"
                }
            },
            "request": "launch"
        }
    ]
}

For running unit tests on MacOSx no extra steps are needed.

Comments
  • Doesn't build with dart 2.13 (Flutter 2.2)

    Doesn't build with dart 2.13 (Flutter 2.2)

    The following function was removed in dart 2.13 and is used in the jscore-bindings:

    @Deprecated('Hold on to the pointer backing a struct instead.')
    Pointer<T> get addressOf => _addressOf as Pointer<T>;
    
    opened by tvh 9
  • Promises don't work

    Promises don't work

    version: 0.2.2+0

    the following code never prints "after promise":

    async function start() {
        console.log('before promise');
        await Promise.resolve('test');
        console.log('after promise');
    }
    

    In the flutter code, I call widget.jsRuntime.enableHandlePromises() and widget.jsRuntime.evaluate("start()");.

    "before promise" is successfuly printed, but the execution hangs in the promise, even if it's already fulfilled. "after promise" is never printed.

    Tested in Android

    opened by Tiagoperes 7
  • Support isolate

    Support isolate

    My JS code is enormous computation. I have to call it on non-main isolate. But I can't do it cause of a crash: "Unhandled Exception: Exception: Null check operator used on a null value". The reason is spawned isolates do not have access to the root bundle https://github.com/flutter/flutter/issues/61480#issuecomment-673985944

    This demo shows what I want.

    import 'package:flutter/foundation.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_js/flutter_js.dart';
    
    void main() async {
      runApp(MaterialApp(
        home: Scaffold(
          body: Center(child: Text("hello word")),
        ),
      ));
    
      final jsCode = "2+3;";
    
      // This code has error: "Unhandled Exception: Exception: Null check operator used on a null value".
      final String result = await compute(_execute, jsCode);
    
      // This code works fine.
      // final int result = await _execute(jsCode);
      print(result);
    }
    
    Future<T> _execute<T>(String jsCode) async {
      final javascriptRuntime = getJavascriptRuntime();
      final result = javascriptRuntime.evaluate(jsCode);
      return javascriptRuntime.convertValue(result);
    }
    
    opened by 623637646 4
  • Webpack configuration for bundling libraries compatible with flutter_js

    Webpack configuration for bundling libraries compatible with flutter_js

    Hi @abner, first and foremost, thank you for this awesome library!

    I have currently have an issue where I am trying to load our own JavaScript library which is bundled with webpack as an UMD library. I managed load a generic JavaScript file containing some test functions and executing them afterwards using the AJV example. Loading the bundled library in a browser using a "script"-tag in an HTML-file works fine, its available in the window/global namespace. However, when I'm trying to load the library using flutter_js, it does not become available in the global namespace.

    I saw you mentioning that you are using webpack to bundle libraries you load into flutter_js. Therefore, I wanted to ask if you could kindly share your webpack.config.js and how you are exporting you library to the global namespace? Afterwards I could do a PR to enhance to documentation on how to embed libraries, if you'd like me to.

    This is the library I am trying to embed: index.js

    The export in the library is done this way:

    class Render {
    ...}
    module.exports = Render;
    

    I also tried export default class {...} which also worked fine in a browser but not in flutter_js.

    This is the webpack.config.js:

    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'open-decision-js-core.js',
        library: {
            name: 'OpenDecisionJSCore',
            type: 'umd',
          },
      },
    };
    

    The loading of the library in flutter follows your example:

    String libJS =
                await rootBundle.loadString("assets/js/open-decision-js-core.js");
    
            this.jsRuntime.evaluate("""var window = global = globalThis;""");
    
            this.jsRuntime.evaluate("$libJS");
    

    However, in the following calls, global.OpenDecisionJSCore is undefined.

    I'd really appreciate some guidance!

    opened by fbennets 4
  • crash when reuse JavascriptRuntime instance

    crash when reuse JavascriptRuntime instance

    F/libc (11765): Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xc5381d58 in tid 11794 (1.ui), pid 11765 (com.app)


    Build fingerprint: 'google/sdk_gphone_x86_arm/generic_x86_arm:11/RSR1.201013.001/6903271:userdebug/dev-keys' Revision: '0' ABI: 'x86' Timestamp: 2020-12-22 01:40:36+0000 pid: 11765, tid: 11794, name: 1.ui >>> com.app <<< uid: 10154 signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xc5381d58 eax c5381d58 ebx b087cc18 ecx c4adcaff edx ffffffff edi c373f910 esi f4411780 ebp c373f908 esp c373f8e0 eip b079a68a backtrace: #00 pc 0001a68a /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #01 pc 0004006b /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #02 pc 00035115 /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #03 pc 00025f1b /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #04 pc 00042793 /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #05 pc 0004e7ed /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #06 pc 00042af6 /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #07 pc 000429d8 /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (JS_Eval+216) (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #08 pc 000085b5 /data/app/~~7QayOaFJendF_Gas0AwqMA==/com.app-2XP4A1LweVaYzb45e0av4g==/lib/x86/libfastdev_quickjs_runtime.so (JSEvalWrapper+165) (BuildId: 3ff1dc3d93b4aab2ab87aadff0bdff8e59b2b960) #09 pc 000033d7 anonymous:c2580000 Lost connection to device.

    opened by cacard 4
  • Code Comments/Explanation

    Code Comments/Explanation

    Hi Abner,

    On the example provided when you want to load a javascript you load the ajv.js library like this:

    String ajvJS = await rootBundle.loadString("assets/js/ajv.js");
    widget.jsRuntime.evaluate("var window = global = globalThis;");
    await widget.jsRuntime.evaluateAsync(ajvJS + "");
    
    
    

    Could you explain those three lines of code?

    I'm trying to load the ssim.js library which natively take less than 50 ms to provide a result. But using flutter_js it takes around 1500 ms. I'm trying to find out where is the bottle neck since I have to evaluate this function 300 times. The time passes from 9 seconds to around 5 minutes.

    This is my code

    String ssimJS = await rootBundle.loadString("assets/SSIM/dist/image-ssim.min.js");
    widget.jsRuntime.evaluate("var window = global = globalThis;");
    await widget.jsRuntime.evaluateAsync(ssimJS + "");
    JsEvalResult evalSsim = widget.jsRuntime.evaluate(""" ssim('image1','image2')"""");
    
    
    opened by mlopez0 4
  • On starting the app in debug mode, getting an error

    On starting the app in debug mode, getting an error

    C:\src\flutter.pub-cache\hosted\pub.dartlang.org\flutter_js-0.0.3+2\android\src\main\kotlin\io\abner\flutter_js\JSEngine.kt: (8, 46): Unresolved reference: JsBridgeConfig e: C:\src\flutter.pub-cache\hosted\pub.dartlang.org\flutter_js-0.0.3+2\android\src\main\kotlin\io\abner\flutter_js\JSEngine.kt: (13, 46): Unresolved reference: JsBridgeConfig

    FAILURE: Build failed with an exception.

    • What went wrong: Execution failed for task ':flutter_js:compileDebugKotlin'.
    opened by Braj65 4
  • Result discrepancy using RRule.js library on Android vs iOS

    Result discrepancy using RRule.js library on Android vs iOS

    Hi I quickly threw together a test to see if I could make use of the RRule.js library to process calendar event recurrence rules. The snippet below should return an array of strings representing UTC dates. However instead I get [{}, {}, {}, {}...] on Android and a comma separated list of dates on iOS. Am I missing a step in regards to parsing the actual result? Great library BTW =)

    `JavascriptRuntime flutterJs = getJavascriptRuntime();

    String ajvJS = await rootBundle.loadString("assets/js/rrule.min.js");
    flutterJs.evaluate("""var window = global = globalThis;""");
    flutterJs.evaluate(ajvJS + "");
    
    var rruleIsLoaded = flutterJs
        .evaluate("""var rruleIsLoaded = (typeof rrule == 'undefined') ? 
          "0" : "1"; rruleIsLoaded;
        """).stringResult;
    print("RRule is Loaded $rruleIsLoaded");
    
    var expression = """const rule = rrule.rrulestr('DTSTART:20120201T093000Z\\nRRULE:FREQ=WEEKLY;INTERVAL=5;UNTIL=20130130T230000Z;BYDAY=MO,FR')""";
    flutterJs.evaluate(expression);
    
    JsEvalResult result = flutterJs.evaluate("""rule.between(new Date(Date.UTC(2012, 1, 1)), new Date(Date.UTC(2013, 1, 1)))""");
    
    print(result);`
    
    opened by SApolinario 3
  • Error in Linux Desktop

    Error in Linux Desktop

    Getting below error on Linux Desktop. Did not find any specific error for flutter js. However, the app works fine if I remove this package. I am using flutter_js: ^0.5.0+5

    [+10312 ms] Exception: Build process failed
    [   +3 ms] "flutter run" took 28,056ms.
    [  +24 ms] 
               #0      throwToolExit (package:flutter_tools/src/base/common.dart:10:3)
               #1      RunCommand.runCommand (package:flutter_tools/src/commands/run.dart:674:9)
               <asynchronous suspension>
               #2      FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1140:27)
               <asynchronous suspension>
               #3      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #4      CommandRunner.runCommand (package:args/command_runner.dart:209:13)
               <asynchronous suspension>
               #5      FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:288:9)
               <asynchronous suspension>
               #6      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #7      FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:236:5)
               <asynchronous suspension>
               #8      run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:62:9)
               <asynchronous suspension>
               #9      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
               <asynchronous suspension>
               #10     main (package:flutter_tools/executable.dart:94:3)
               <asynchronous suspension>
    
    opened by inoerp 3
  • If javascript package code  depends on other modules ,code has require statement.What shoud i do?

    If javascript package code depends on other modules ,code has require statement.What shoud i do?

    I use turndown,it's a html to markdown convert.It depends on domino.

    What shoud i do ?

    The flutter_js can support the implementation of require('assets://xxxx.js')?

    opened by hjue 3
  • Latest version of flutter_js 0.5.0+0 is not working

    Latest version of flutter_js 0.5.0+0 is not working

    I am using flutter_js 0.5.0+0 and Flutter 2.2.2, everything is working fine under simulator but fails on physical device (tested on two different Android phones). Something wrong with returned values - app is stuck when, let's say, jsonDecode applied onto jsResult.stringResult. Even demo app flutter_js_example supplied with a package has the same behavior, works under simulator, fails on real device.

    Previous combination (flutter_js 0.4.0+6 and Flutter 2.0.5) worked without issues.

    opened by ashemetov 3
  • This JS code returns an error condition in the library but runs fine in a browser & node.js

    This JS code returns an error condition in the library but runs fine in a browser & node.js

    The code in question transforms a string in an obfuscated manner. It is designed to be difficult to emulate. It is pure javascript, however, with no external dependencies.

     function transform(nCode) {
      var ala = function (a) {
        var b = a.split(""), c = [function (d, e) { e = (e % d.length + d.length) % d.length; d.splice(-e).reverse().forEach(function (f) { d.unshift(f) }) },
        -1921058111, -550767080, 700635937, -681127572, -2036895570, '"\\[,;{(', 573397093, "case", function (d, e) { e.splice(e.length, 0, d) },
          1531196722, 633332557, 528984348, -1607694989, 1055836676, 1918638563, /\/[[\],],}[);"](\\)/, -961585583, function (d, e, f, h, l) { return e(f, h, l) },
          '"\\]{', -163811383, function (d) { for (var e = d.length; e;)d.push(d.splice(--e, 1)[0]) },
        function (d, e, f, h, l, m) { return e(h, l, m) },
        -412319399, function () { for (var d = 64, e = []; ++d - e.length - 32;)switch (d) { case 58: d = 96; continue; case 91: d = 44; break; case 65: d = 47; continue; case 46: d = 153; case 123: d -= 58; default: e.push(String.fromCharCode(d)) }return e },
        function (d, e) { for (e = (e % d.length + d.length) % d.length; e--;)d.unshift(d.pop()) },
        -32381959, 885725605, function () { for (var d = 64, e = []; ++d - e.length - 32;) { switch (d) { case 91: d = 44; continue; case 123: d = 65; break; case 65: d -= 18; continue; case 58: d = 96; continue; case 46: d = 95 }e.push(String.fromCharCode(d)) } return e },
        -1312226002, 2063686934, 2085930185, 576539933, function (d, e) { d = (d % e.length + e.length) % e.length; e.splice(0, 1, e.splice(d, 1, e[0])[0]) },
        function () { for (var d = 64, e = []; ++d - e.length - 32;) { switch (d) { case 58: d -= 14; case 91: case 92: case 93: continue; case 123: d = 47; case 94: case 95: case 96: continue; case 46: d = 95 }e.push(String.fromCharCode(d)) } return e },
          2056862263, 1375054214, -1350068165, 1766781546, -1543464133, -2047101538, 1096253002, -1609890806, 744789249, -1489867586, 125155855, -887105894, function (d, e) { d = (d % e.length + e.length) % e.length; e.splice(d, 1) },
        -1986842888, function (d, e, f, h, l, m, n, p) { return d(m, n, p) },
          2064682343, -1533195787, 466091162, 810599612, -578194583, null, b, 1277323162, -1815627253, function (d) { d.reverse() },
        -1601555489, function (d, e, f, h, l, m, n, p) { return e(f, h, l, m, n, p) },
        function (d, e, f) { var h = d.length; f.forEach(function (l, m, n) { this.push(n[m] = d[(d.indexOf(l) - d.indexOf(this[m]) + m + h--) % d.length]) }, e.split("")) },
        function (d, e) { e.push(d) },
          504398874, 281244892, -1992584841, -1832354004, b, function (d, e) { e = (e % d.length + d.length) % d.length; var f = d[0]; d[0] = d[e]; d[e] = f },
          null, 1654194707, 60495725, 1987139773, -1553802360, -104589219, 1838355129, function () { for (var d = 64, e = []; ++d - e.length - 32;)switch (d) { case 46: d = 95; default: e.push(String.fromCharCode(d)); case 94: case 95: case 96: break; case 123: d -= 76; case 92: case 93: continue; case 58: d = 44; case 91: }return e },
          1592131649, -71282267, -704854045, 566447420, b, 1507988747, null, -2040686642, -460220910, 633332557, 682194956]; c[55] = c; c[70] = c; c[84] = c; try {
            try {
              -6 !== c[54] && (0 > c[88] && ((0, c[33])(c[27], c[84]), 1) || (0, c[69])(c[56], c[38])), 9 > c[3] && ((((0, c[33])(c[65], c[82]), c[62])((0, c[77])(), c[8], c[82]), c[18])((0, c[18])((0, c[62])((0, c[new Date("December 31 1969 17:15:34 -0645") / 1E3])(), c[8], c[68]) * (0, c[69])(c[68], c[new Date("December 31 1969 17:01:26 PDT") / 1E3]) === (0, c[62])((0, c[77])(), c[8], c[82]), c[69], c[56], c[37]), c[21], c[70]),
                (0, c[0])(c[56], c[76]), 1) || (0, c[22])((0, c[21])(c[Math.pow(6, 3) - 53 + -107]), c[25], (0, c[61])((0, c[62])((0, c[77])(), c[8], c[56]), c[22], (0, c[18])((0, c[21])(c[56]), c[21], c[56]), c[0], ((0, c[25])(c[82], c[20]), c[69])(c[82], c[71]), c[55], c[15]), c[40], c[2])
            } catch (d) { (0, c[403 % Math.pow(7, 1) - -53])((0, c[86])(c[62], c[20]), c[64], c[20], c[75]) } try {
              -10 !== c[21] && (c[53] === new Date("Wednesday 31 December 1969 18:00:08 MDT") / 1E3 ? (0, c[12])((0, c[67])(), c[47], c[6]) : (0, c[72])(c[25], c[34])), 10 <= c[36] && ((((0, c[12])((0, c[63])(), c[47],
                c[18]), c[new Date("Wednesday December 31 1969 16:00:12 PST") / 1E3])((0, c[67])(), c[47], c[32]), c[12])((0, c[73])(), c[47], c[18]), 1) || (0, c[57])((0, c[57])((0, c[39])(c[5], c[3]), c[22], c[77], c[20]), c[15], c[16], c[29])
            } catch (d) { (0, c[60])(c[14], c[77]), (0, c[8])((0, c[63])(), c[43], c[14]) } try {
              8 != c[31] ? (0, c[53])((0, c[53])((0, c[68])(c[61], c[30]), c[new Date("1970-01-01T09:45:15.000+09:45") / 1E3], c[2], c[66]), c[5], c[30]) : (0, c[35])(((0, c[6])(c[61], c[58]), c[6])(c[78], c[60]), c[88], c[39], c[74]), (-1 != c[8] || ((0, c[new Date("December 31 1969 15:15:28 -0845") /
                1E3])(c[58], c[new Date("Wednesday 31 December 1969 19:00:36 EST") / 1E3]), 0)) && (0, c[6])(c[82], c[74]), -3 <= c[3] && ((0, c[88])(c[41], c[86]), c[35])((0, c[88])(c[Math.pow(8, 3) % 261 - 203], c[Math.pow(1, 1) % 414 - -57]), c[28], c[87], c[76]), -5 !== c[74] && (((0, c[29])(c[78], (0, c[24])(c[26], c[58 - Math.pow(4, 5) % 247]), (0, c[9])(c[22], c[45]), (0, c[new Date("12/31/1969 17:00:53 MST") / 1E3])(c[22], c[6]), ((0, c[69])(c[82], c[23]), c[53])(c[83], c[77]), c[89], c[68]), c[49])((0, c[42])(c[89], c[28]), c[13], c[27], c[89]) <= ((0, c[4])(c[37], c[72]),
                  c[new Date("1969-12-31T17:00:20.000-07:00") / 1E3])(c[86], c[74]) <= (0, c[49])((((0, c[13])(c[26], c[12]), c[88])(c[72], c[10]), (0, c[88])(c[72], c[90]), c[8])(c[87]), c[77], c[6], c[18]), ",") || ((((0, c[41])((0, c[41])((0, c[85])((0, c[57])(), c[-78 * Math.pow(1, 4) - -109], c[1]), c[70], c[36], c[79]), c[77], c[54], c[1]), c[41])((0, c[41])((0, c[76 - Math.pow(8, 5) + 32762])(c[7], c[79]), c[44], c[1]), c[85], (0, c[47])(), c[31], c[79]) > (0, c[41])((0, c[41])((0, c[48])(c[16], c[74]), c[70], c[52], c[1]), c[70], c[81], c[16]), (0, c[85])((0, c[10])(), c[31],
                    c[16]), c[48])(c[16], c[69]), c[new Date("January 01 1970 00:00:41 GMT") / 1E3])((0, c[70])(c[25], c[-5586 + Math.pow(3, 1) - -5661]), c[77], c[27], c[18]) <= (0, c[70])(c[68], c[16]) < (0, c[82])(c[3])
            } catch (d) { ((0, c[48])(c[16], c[14]), c[2])(c[1653 + Math.pow(2, 3) - 1658], c[67]), (0, c[85])((0, c[57])(), c[31], c[1]), (0, c[70])(c[71], c[79]) } try {
              9 < c[30] && (((0, c[70])(c[26], c[1]), c[23])(c[79], c[30]), /({)/) || ((0, c[70])(c[19], c[79]), c[70])(c[64], c[18]), -1 == c[83] ? (0, c[41])((0, c[82])(c[1]), c[82], c[79]) : (0, c[41])((0, c[48])(c[3], c[58]),
                c[36], c[21], c[47])
            } catch (d) { (0, c[36])(c[37], c[45]), (0, c[82])(c[21], c[67]) }
          } catch (d) { return "enhanced_except_hZcB-uj-_w8_" + a } return b.join("")
      }; return ala(nCode);
    }
    transform('jM4AdVF7yBo4huh5I');
    

    In my browser this code produces the result '1Zx9iSk1emsfzQ'. I get the same result from nodejs when changing the last line to console.log( transform('jM4AdVF7yBo4huh5I') ); I also get the same result in jsfiddle.

    But in flutter_js with the above code in a String variable transformFn and running as follows

       JsEvalResult jsEvalResult = runtime.evaluate( transformFn );
       return jsEvalResult.stringResult;
    

    I get the result: enhanced_except_hZcB-uj-_w8_zCNZQZpiBU8WZ-xlR

    which is you can see is returned from an error catch block.

    If I replace "enhanced_except_hZcB-uj-_w8_"+a with d.message the code via the library returns not a function.

    Hopefully this a clue as to what is breaking the JS emulation.

    Run with flutter_js 0.6.0 on Windows 10.

    opened by gatecrasher777 0
  • [linux] `libquickjs_c_bridge_plugin.so` saved in wrong folder

    [linux] `libquickjs_c_bridge_plugin.so` saved in wrong folder

    It's strange, it exists in my local machine, but when building with github action, it disappeared. Run with flutter build -v, it said "Installing .../libquickjs_c_bridge_plugin.so", but actually it saved to build/linux/x64/release/plugins/flutter_js/bundle/lib/.

    You can check action logs here: https://github.com/chaldea-center/chaldea/actions/runs/3631150418/jobs/6125394018

    [        ] -- Installing: /home/runner/work/chaldea/chaldea/build/linux/x64/release/bundle/lib/libapp.so
    [        ] -- Installing: /home/runner/work/chaldea/chaldea/build/linux/x64/release/plugins/flutter_js/bundle/lib/libquickjs_c_bridge_plugin.so
    [  +10 ms] Building Linux application... (completed in 88.3s)
    [   +1 ms] "flutter linux" took 88,988ms.
    [   +2 ms] ensureAnalyticsSent: 0ms
    [        ] Running 0 shutdown hooks
    [        ] Shutdown hooks complete
    [        ] exiting with code 0
    
    lib/:
    total 32916
    -rw-r--r-- 1 runner docker 18563992 Dec  6 15:57 libapp.so
    -rw-r--r-- 1 runner docker    22808 Dec  6 15:57 libflutter_js_plugin.so
    -rw-r--r-- 1 runner docker 15028648 Dec  6 15:56 libflutter_linux_gtk.so
    -rw-r--r-- 1 runner docker    22704 Dec  6 15:57 libflutter_window_close_plugin.so
    -rw-r--r-- 1 runner docker    23784 Dec  6 15:57 liburl_launcher_linux_plugin.so
    -rw-r--r-- 1 runner docker    29608 Dec  6 15:57 libwindow_size_plugin.so```
    opened by narumi147 1
  • How to call callFunction

    How to call callFunction

    I have a string function const test =()=>{ return 'test' } Please tell me how to call javascriptRuntime. callFunction. Can you give an example Thank you very much.

    opened by lsdlh 3
  • Does this work with visual JS libraries? (e.g. Chart.js or D3.js)

    Does this work with visual JS libraries? (e.g. Chart.js or D3.js)

    If it does, could you please give us a simple example?

    This would be incredibly useful because visual libraries in JS are exponentially more capable than those in Flutter.

    opened by psygo 0
  • QuickJS: ConvertValue() always returns true

    QuickJS: ConvertValue() always returns true

    Maybe this should be throwing a "not implemented" error for now?

    https://github.com/abner/flutter_js/blob/0fce4c80e84a3564a6d068209070f914e773e019/lib/quickjs/quickjs_runtime2.dart#L204

    opened by ted537 0
Releases(0.5.0+0)
Owner
Ábner Oliveira
Ábner Oliveira
A light-weight Flutter Engine Embedder for Raspberry Pi that runs without X.

?? NEWS The new latest flutter gallery commit for flutter 2.2 is 633be8a There's now a #custom-embedders channel on the flutter discord which you can

Hannes Winkler 1.1k Jan 1, 2023
Yocto meta layer for recipes related to using Google Flutter Engine

meta-flutter Notice: Layer has moved to https://github.com/meta-flutter/meta-flutter. Redirection will be automatic in the next couple of weeks. Yocto

Joel Winarske 46 Dec 4, 2022
Reversi Board with edax, which is the strongest reversi engine.

pedax pedax is Board GUI with edax, which is the strongest reversi program. pedax has 4 features. Mac/Windows/Linux are supported. I distribute on Mac

done 19 Dec 14, 2022
File picker plugin for Flutter, compatible with mobile (iOS & Android), Web, Desktop (Mac, Linux, Windows) platforms with Flutter Go support.

A package that allows you to use the native file explorer to pick single or multiple files, with extensions filtering support.

Miguel Ruivo 987 Jan 6, 2023
Android-Toolbox is a desktop app which enables the user to access android device features which are not accessible directly from the mobile device

Android-Toolbox is a desktop app which enables the user to access android device features which are not accessible directly from the mobile device. One of Android-Toolbox's special feature is to transfer files at the highest speed using ADB push and pull bypassing a lot of Android API overheads.

Sashank Visweshwaran 30 Dec 26, 2022
A project that makes use of a Typescript back end and a Flutter web front end to consume the Jira API in order to visualize and interact with issues.

A project that makes use of a Typescript back end and a Flutter web front end to consume the Jira API in order to visualize and interact with issues.

Lucas Coelho 1 Mar 20, 2022
Windows95 UI components for Flutter apps. Bring back the nostalgic look and feel of old operating systems with this set of UI components ready to use.

Flutter95 Windows95 UI components for Flutter apps. UNDER CONSTRUCTION Screenshots Components Scaffold95 Scaffold as a Windows95 styled window. Provid

Miguel Beltran 141 Dec 26, 2022
A simple-to-use flutter update package for Windows, MacOS, and Linux.

Updat - The simple-to-use, flutter-based desktop update package Updat is a simple-to-use reliable flutter-native updater that handles your application

Eduardo M. 14 Dec 21, 2022
Use Dart to call Shell, complete the work of compiling Golang CGO code into a so, dll, a, WASM, and etc.

Use Dart to call Shell, complete the work of compiling Golang CGO code into a so, dll, a, WASM, and etc. And place it in the corresponding source file directory of each Flutter platform.

Dorain Gray 30 Dec 30, 2022
Flutter date range pickers use a dialog window to select a range of date on mobile.

[Deprecated] Date Range Picker Currently Flutter has supported date range picker, so I think my mission is done. Thanks for using my lib. Link: https:

null 225 Dec 28, 2022
A cross-platform app ecosystem, bringing iMessage to Android, PC (Windows, Linux, & even macOS), and Web!

BlueBubbles Android App BlueBubbles is an open-source and cross-platform ecosystem of apps aimed to bring iMessage to Android, Windows, Linux, and mor

BlueBubbles 318 Jan 8, 2023
A Flutter plugin to read 🔖 metadata of 🎵 media files. Supports Windows, Linux & Android.

flutter_media_metadata A Flutter plugin to read metadata of media files. A part of Harmonoid open source project ?? Install Add in your pubspec.yaml.

Harmonoid 60 Dec 2, 2022
A cross-platform (Android/Windows/macOS/Linux) USB plugin for Flutter

quick_usb A cross-platform (Android/Windows/macOS/Linux) USB plugin for Flutter Usage List devices List devices with additional description Get device

Woodemi Co., Ltd 39 Oct 1, 2022
Flutter on Windows, MacOS and Linux - based on Flutter Embedding, Go and GLFW.

go-flutter - A package that brings Flutter to the desktop Purpose Flutter allows you to build beautiful native apps on iOS and Android from a single c

null 5.5k Jan 6, 2023
Serverpod is a next-generation app and web server, explicitly built for the Flutter and Dart ecosystem.

Serverpod Serverpod is a next-generation app and web server, explicitly built for the Flutter and Dart ecosystem. It allows you to write your server-s

Serverpod 1k Jan 8, 2023
A material theme editor and generator for Flutter to configure and preview the overall visual theme of your material app

A material theme editor and generator for Flutter to configure and preview the overall visual theme of your material app

Joshua 301 Jan 3, 2023
A fresh and modern Google Contacts manager that integrates with GitHub and Twitter.

Flokk A fresh and modern Google Contacts manager that integrates with GitHub and Twitter. Demo Builds Web: https://flokk.app Linux: https://snapcraft.

gskinner team 1.3k Jan 3, 2023
My Notes is an app to create simple notes and add 3 levels of tags to them. The uniqueness of the app lies in its design and dark theme

?? My Notes | Simple & Beautiful Note Taking App ?? About The App ?? My Notes is an app to create simple notes and add 3 levels of tags to them. The u

null 4 Apr 27, 2022
A web dashboard that allows you to monitor your Chia farm and sends notifications when blocks are found and new plots are completed through a discord bot. It can link multiple farmers/harvesters to your account.

farmr A web dashboard that allows you to monitor your Chia farm and sends notifications when blocks are found and new plots are completed through a di

Gil Nobrega 261 Nov 10, 2022