|
3 | 3 | [](https://ethanblake.xyz/evalpad)
|
4 | 4 |
|
5 | 5 | `flutter_eval` is a Flutter bridge library for [dart_eval](https://pub.dev/packages/dart_eval),
|
6 |
| -enabling painless creation of fully dynamic Flutter apps and widgets that can be loaded |
7 |
| -from a file or the Internet at runtime. It provides both a set of compile-time descriptors and directives, |
8 |
| -as well as runtime bridge classes and wrappers, with a seamless API that makes usage easy. |
| 6 | +and a solution enabling both fully dynamic runtime code-push and runtime evaluation of Flutter code. |
| 7 | +It can be used to enable hot-swapping parts of your app with an over-the-air update, or for dynamically |
| 8 | +evaluating code based on user input such as in a calculator. flutter_eval supports all platforms |
| 9 | +including iOS and is built on dart_eval's custom bytecode interpreter, making it very fast. |
9 | 10 |
|
10 | 11 | | dart_eval | [](https://pub.dev/packages/dart_eval) |
|
11 | 12 | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
|
12 | 13 | | flutter_eval | [](https://pub.dev/packages/flutter_eval) |
|
| 14 | +| eval_annotation | [](https://pub.dev/packages/eval_annotation) | |
13 | 15 |
|
14 | 16 | For a live example, check out [EvalPad](https://ethanblake.xyz/evalpad).
|
15 | 17 |
|
16 | 18 | Although flutter_eval is already the best solution for native Dart Flutter code push,
|
17 |
| -it's still very early for the project and you should not expect existing Flutter/Dart code |
18 |
| -to work without modification. Many classes and methods have not yet been implemented. |
| 19 | +the project is still in development and you should not expect all existing Flutter/Dart code |
| 20 | +to work without modification, as various standard library classes and Dart features |
| 21 | +have yet to be implemented. |
19 | 22 |
|
20 |
| -## Getting started |
| 23 | +## Quickstart for code push |
21 | 24 |
|
22 | 25 | Run `flutter pub add flutter_eval` to install the package.
|
23 | 26 |
|
| 27 | +At the root of your app, add a HotSwapLoader widget with a URI |
| 28 | +pointing to where you'll host the update file: |
| 29 | + |
| 30 | +```dart |
| 31 | +class MyApp extends StatelessWidget { |
| 32 | +
|
| 33 | + @override |
| 34 | + Widget build(BuildContext context) { |
| 35 | + return HotSwapLoader( |
| 36 | + uri: 'https://mysite.com/app_update/version_xxx.evc', |
| 37 | + child: MaterialApp( |
| 38 | + ... |
| 39 | +``` |
| 40 | + |
| 41 | +Then, add HotSwap widgets throughout your app at every location |
| 42 | +you'd like to be able to dynamically update: |
| 43 | + |
| 44 | +```dart |
| 45 | +class MyHomePage extends StatelessWidget { |
| 46 | + |
| 47 | + @override |
| 48 | + Widget build(BuildContext context) { |
| 49 | + return HotSwap( |
| 50 | + id: '#myHomePage', |
| 51 | + args: [$BuildContext.wrap(context)], |
| 52 | + childBuilder: (context) => Scaffold( |
| 53 | + ... |
| 54 | +``` |
| 55 | + |
| 56 | +Next, create a new Flutter package using `flutter create --template=package`. |
| 57 | +This can be nested inside your app's folder or located separately. Name it |
| 58 | +something appropriate, such as my_app_hot_update. We'll refer to this |
| 59 | +as the "hot update package" from now on. |
| 60 | + |
| 61 | +Head over to the flutter_eval [Releases page](https://github.com/ethanblake4/flutter_eval/releases) |
| 62 | +and find the release corresponding to the version of flutter_eval you are using. Under **Assets**, |
| 63 | +download `flutter_eval.json`. (Or [click here](https://github.com/ethanblake4/flutter_eval/releases/latest/download/flutter_eval.json) to download the latest version.) |
| 64 | + |
| 65 | +In the root of the hot update package, create a folder called `.dart_eval` and |
| 66 | +a subfolder `bindings`. Place the downloaded `flutter_eval.json` file inside of |
| 67 | +this folder. |
| 68 | + |
| 69 | +Your project structure should look like this: |
| 70 | +``` |
| 71 | +├── .dart_eval |
| 72 | +│ └── bindings |
| 73 | +│ └── flutter_eval.json. |
| 74 | +├── pubspec.yaml |
| 75 | +└── lib |
| 76 | + └── hot_update.dart |
| 77 | +``` |
| 78 | + |
| 79 | +At the root of the hot update package, run `flutter pub add eval_annotation`. |
| 80 | + |
| 81 | +Delete all the code from main.dart, including the main() function. |
| 82 | +For every HotSwap widget you'd like to update (you can update all, |
| 83 | +or just a few, or just one), create a top-level function with the |
| 84 | +@RuntimeOverride annotation referencing its ID: |
| 85 | + |
| 86 | +```dart |
| 87 | +@RuntimeOverride('#myHomePage') |
| 88 | +Widget myHomePageUpdate(BuildContext context) { |
| 89 | + return Scaffold( |
| 90 | + ... |
| 91 | + ) |
| 92 | +} |
| 93 | +``` |
| 94 | +Finally, we'll need to install the dart_eval CLI: |
| 95 | + |
| 96 | +```bash |
| 97 | +dart pub global activate dart_eval |
| 98 | +``` |
| 99 | + |
| 100 | +After installing, you can run: |
| 101 | +```bash |
| 102 | +dart_eval compile -o version_xxx.evc |
| 103 | +``` |
| 104 | + |
| 105 | +If the steps were performed correctly, you should see the following in the console output: |
| 106 | + |
| 107 | +`Found binding file: .dart_eval\bindings\flutter_eval.json` |
| 108 | + |
| 109 | +as well as |
| 110 | + |
| 111 | +`Compiled $x characters Dart to $y bytes EVC in $z ms: version_xxx.evc` |
| 112 | + |
| 113 | +The resulting `version_xxx.evc` file will be in the root of the project and |
| 114 | +you can now upload it to the previously referenced server path. |
| 115 | + |
| 116 | +If you run the app, you should see the contents of the HotSwap widgets |
| 117 | +replaced with the contents of their corresponding @RuntimeOverride functions. |
| 118 | + |
| 119 | +HotSwap widgets can optionally specify a strategy to use when loading/applying updates, |
| 120 | +one of _immediate_, _cache_, or _cacheApplyOnRestart_. By default, HotSwapLoader |
| 121 | +uses immediate in debug/profile mode and cacheApplyOnRestart in release mode. You |
| 122 | +can also specify a placeholder widget to display when loading from the cache via |
| 123 | +the _loading_ parameter. |
| 124 | + |
| 125 | +For a complete example of code push, see |
| 126 | +[examples/code_push_app](https://github.com/ethanblake4/flutter_eval/tree/master/examples/code_push_app) |
| 127 | +and its subfolder [hot_update](https://github.com/ethanblake4/flutter_eval/tree/master/examples/code_push_app/hot_update). |
| 128 | + |
| 129 | +## Quickstart for dynamic execution and manual updates |
| 130 | + |
24 | 131 | To create a simple dynamic stateless widget, add and modify the following inside a
|
25 | 132 | build() method or as a child parameter:
|
26 | 133 |
|
@@ -82,69 +189,8 @@ flutter_eval includes two other helper Widgets for different use cases:
|
82 | 189 | - `RuntimeWidget` will *always* load EVC bytecode and does not provide a
|
83 | 190 | parameter to specify Dart code. This is recommended if you're compiling
|
84 | 191 | with the CLI - see below.
|
85 |
| - |
86 |
| -## Compiling with the dart_eval CLI |
87 |
| - |
88 |
| -flutter_eval allows you to compile an existing Flutter project using the dart_eval CLI; |
89 |
| -please note, however, that Pub packages are not currently supported. |
90 |
| - |
91 |
| -To get started, first install the dart_eval CLI: |
92 |
| - |
93 |
| -```bash |
94 |
| -dart pub global activate dart_eval |
95 |
| -``` |
96 |
| - |
97 |
| -Next, head over to the flutter_eval [Releases page](https://github.com/ethanblake4/flutter_eval/releases) |
98 |
| -and find the release corresponding to the version of flutter_eval you are using. Under **Assets**, |
99 |
| -download `flutter_eval.json`. |
100 |
| - |
101 |
| -In the root of the project you wish to compile, create a folder called `.dart_eval` and |
102 |
| -a subfolder `bindings`. Place the downloaded `flutter_eval.json` file inside of this folder. |
103 |
| - |
104 |
| -Your project structure should look like this: |
105 |
| -``` |
106 |
| -├── .dart_eval |
107 |
| -│ └── bindings |
108 |
| -│ └── flutter_eval.json. |
109 |
| -├── pubspec.yaml |
110 |
| -└── lib |
111 |
| - └── main.dart |
112 |
| -``` |
113 |
| - |
114 |
| -You'll also have to change your entrypoint a bit. flutter_eval does not support |
115 |
| -`runApp()` as it runs inside an existing Flutter app, which already calls runApp(). |
116 |
| -Instead, you can change your main() function to look like this: |
117 |
| - |
118 |
| -```dart |
119 |
| -Widget main() { |
120 |
| - // do any setup, then |
121 |
| - return MyApp(); |
122 |
| -} |
123 |
| -``` |
124 |
| - |
125 |
| -Alternatively, you can simply comment out runApp() and reference Widget |
126 |
| -constructors directly from RuntimeWidget. This is recommended if your project |
127 |
| -has multiple widgets which are displayed at different times or in different |
128 |
| -parts of the app. |
129 |
| - |
130 |
| -Finally, in the root of your project, run: |
131 |
| -```bash |
132 |
| -dart_eval compile -o program.evc |
133 |
| -``` |
134 |
| - |
135 |
| -If the steps were performed correctly, you should see the following in the console output: |
136 |
| - |
137 |
| -`Found binding file: .dart_eval\bindings\flutter_eval.json` |
138 |
| - |
139 |
| -as well as |
140 |
| - |
141 |
| -`Compiled $x characters Dart to $y bytes EVC in $z ms: program.evc` |
142 |
| - |
143 |
| -The resulting `program.evc` file will be in the root of your project and you can use it |
144 |
| -in flutter_eval, as an asset or from a URL. The package name will be automatically inferred |
145 |
| -from your pubspec.yaml file. |
146 |
| - |
147 |
| -## Calling functions and passing arguments |
| 192 | + |
| 193 | +### Calling functions and passing arguments |
148 | 194 |
|
149 | 195 | To instantiate a class with its default constructor, append a '.' to the class name.
|
150 | 196 |
|
@@ -193,7 +239,10 @@ Currently supported widgets and classes include:
|
193 | 239 | - `Text`, `TextStyle`, `TextEditingController`, `TextField`;
|
194 | 240 | - `TextDirection`, `VerticalDirection`, `TextBaseline`
|
195 | 241 | - `Scaffold`, `ScaffoldMessenger`, `AppBar`, `SnackBar`, `FloatingActionButton`;
|
196 |
| -- `TextButton`, `ElevatedButton`, `IconButton`, `Spacer`; |
| 242 | +- `InkWell`, `TextButton`, `ElevatedButton`, `IconButton`; |
| 243 | +- `Card`, `Drawer`; |
| 244 | +- `Image`, `ImageProvider`, `NetworkImage`, `MemoryImage`; |
| 245 | +- `ListView`, `ListTile`, `Spacer`; |
197 | 246 | - `Navigator`, `NavigatorState`, `Builder`;
|
198 | 247 |
|
199 | 248 | Note that many of these have only partial support.
|
|
0 commit comments