Skip to content

Commit 79e2c76

Browse files
committed
Add details on snippet and manual edit mode
1 parent 1c1c641 commit 79e2c76

File tree

4 files changed

+103
-26
lines changed

4 files changed

+103
-26
lines changed

docs/ff-concepts/adding-customization/configuration-files.md

Lines changed: 103 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,67 @@ FlutterFlow provides two main ways to modify native files: [**Add Individual Sni
4242
For Android, modifications are typically made in the `AndroidManifest.xml` file, where you can add the following tags:
4343

4444
- **Activity Tags**: This injects code inside the `<activity> ... </activity>` block. You’d use this to declare an additional activity in an Android application. An activity represents a single screen with a user interface (UI). This tag can control the behavior, orientation, and themes, and determines how the activity interacts with other apps or system events.
45-
- **Application Tags**: [Add info after checking in Beta]
46-
47-
To add a snippet in the `AndroidManifest.xml` file, open **Custom Code** (from the left side navigation menu) **> Configuration Files >** select **`AndroidManifest.xml`**. [add instructions para]
48-
49-
[more info on this (after checking in beta) →When you add an XML snippet, you can give it a name; The name is added as a comment around the snippet in the file]
50-
51-
[Arcade: use example for both the tags]
45+
- **Application Tags**: This injects code inside the `<application> ... </application>` block. You’d use this to configure `<meta-data>` entries, application-wide settings, declare app components like services, broadcast receivers, and content providers, and specify intent filters.
46+
47+
To add a snippet to your `AndroidManifest.xml`, navigate to **Custom Code** from the left navigation menu, select **Configuration Files**, then choose `AndroidManifest.xml`. Click the **plus** (+) button next to either the *Activity* or *Application* tag—depending on where you'd like to insert the snippet. Provide a name (this will be included as a comment in the file) and paste your snippet code.
48+
49+
<div style={{
50+
position: 'relative',
51+
paddingBottom: 'calc(56.67989417989418% + 41px)', // Keeps the aspect ratio and additional padding
52+
height: 0,
53+
width: '100%'}}>
54+
<iframe
55+
src="https://demo.arcade.software/rM4e11x5yCTZMdAE8tqE?embed&show_copy_link=true"
56+
title=""
57+
style={{
58+
position: 'absolute',
59+
top: 0,
60+
left: 0,
61+
width: '100%',
62+
height: '100%',
63+
colorScheme: 'light'
64+
}}
65+
frameborder="0"
66+
loading="lazy"
67+
webkitAllowFullScreen
68+
mozAllowFullScreen
69+
allowFullScreen
70+
allow="clipboard-write">
71+
</iframe>
72+
</div>
73+
<p></p>
5274

5375
#### Snippet Placement for iOS
5476

5577
For iOS, you can modify the `Info.plist` and `Entitlements.plist` files. There’s no nested application/activity structure like on Android. Instead, both files are dictionaries of key-value pairs. When you add a snippet, it’s placed directly under the root `<dict>` element of these plist files.
5678

57-
[write after looking at the feature in beta]
58-
59-
To add a snippet in iOS native files, open **Custom Code** (from the left side navigation menu) **> Configuration Files >** select desired file (`Info.plist` or `Entitlements.plist`). [add intrunctions para]
60-
61-
Here’s an example of adding snippet in [Info.plist] that allows [add info on what you are adding]
62-
63-
Here’s an example of adding snippet in [Entitlements.plist] that allows [add info on what you are adding]
79+
To add a snippet to native iOS files, navigate to **Custom Code** (from the left-side menu) > **Configuration Files**, and select the desired file (`Info.plist` or `Entitlements.plist`). Click the **plus** (+) button, provide a descriptive name (which will appear as a comment in the file), and paste your snippet code.
80+
81+
<div style={{
82+
position: 'relative',
83+
paddingBottom: 'calc(56.67989417989418% + 41px)', // Keeps the aspect ratio and additional padding
84+
height: 0,
85+
width: '100%'}}>
86+
<iframe
87+
src="https://demo.arcade.software/pqR3C1oSlZiPQhpeA19C?embed&show_copy_link=true"
88+
title=""
89+
style={{
90+
position: 'absolute',
91+
top: 0,
92+
left: 0,
93+
width: '100%',
94+
height: '100%',
95+
colorScheme: 'light'
96+
}}
97+
frameborder="0"
98+
loading="lazy"
99+
webkitAllowFullScreen
100+
mozAllowFullScreen
101+
allowFullScreen
102+
allow="clipboard-write">
103+
</iframe>
104+
</div>
105+
<p></p>
64106

65107
:::tip
66108
You can also use your Development [**Environment Values**](../../testing-deployment-publishing/development-environments/development-environments.md#environment-values) and [**Library Values**](../../resources/projects/libraries.md#library-values) inside snippets. For more details, refer to the [**Include Variables in Native Code**](#include-variables-in-native-code) section.
@@ -70,11 +112,37 @@ You can also use your Development [**Environment Values**](../../testing-deploym
70112

71113
For more complex changes, you can enable **Manual Edit Mode**, which essentially unlocks the entire file for free-form editing. This is like opening the raw file in a text editor directly within FlutterFlow. **Note that** the Manual mode is powerful but should be used carefully.
72114

73-
To manually edit the native files, open **Custom Code** (from the left side navigation menu) **> Configuration Files >** select desired file. Now [add instructions after looking in Beta]
115+
To manually edit native files, navigate to **Custom Code** (from the left-side menu) > **Configuration Files**, select the file you want to edit, and click the **lock** button to unlock it. You can now freely modify the file.
74116

75-
[more info about manual edit mode from liner ticket]
117+
:::tip
118+
Once unlocked, the file stays in manual editing mode until you lock it again. Locking it will reset the file to a version generated by FlutterFlow.
119+
:::
76120

77-
[arcade]
121+
<div style={{
122+
position: 'relative',
123+
paddingBottom: 'calc(56.67989417989418% + 41px)', // Keeps the aspect ratio and additional padding
124+
height: 0,
125+
width: '100%'}}>
126+
<iframe
127+
src="https://demo.arcade.software/gbjFJzct9J5Jh4lxOniX?embed&show_copy_link=true"
128+
title=""
129+
style={{
130+
position: 'absolute',
131+
top: 0,
132+
left: 0,
133+
width: '100%',
134+
height: '100%',
135+
colorScheme: 'light'
136+
}}
137+
frameborder="0"
138+
loading="lazy"
139+
webkitAllowFullScreen
140+
mozAllowFullScreen
141+
allowFullScreen
142+
allow="clipboard-write">
143+
</iframe>
144+
</div>
145+
<p></p>
78146

79147
:::tip
80148

@@ -103,6 +171,9 @@ Let’s say you are integrating the Mapbox package in your FlutterFlow app, and
103171

104172
Here, `{{MAPBOX_ACCESS_TOKEN}}` is an Environment Values that FlutterFlow replaces with the actual token at build time.
105173

174+
![variables-in-native-code-example-1](imgs/variables-in-native-code-example-1.avif)
175+
176+
106177
**Example 2: Configuring `Info.plist` for iOS**
107178

108179
For iOS apps, you might need to configure App Transport Security (ATS) to allow non-HTTPS connections. Instead of manually setting `NSAllowsArbitraryLoads` to `true`, you can use a FlutterFlow variable:
@@ -114,6 +185,9 @@ For iOS apps, you might need to configure App Transport Security (ATS) to allow
114185

115186
If `ALLOW_HTTP_TRAFFIC` is set to `true` in FlutterFlow’s Environment Value, the app will allow HTTP connections.
116187

188+
![variables-in-native-code-example-2](imgs/variables-in-native-code-example-2.avif)
189+
190+
117191
**Example 3: Using Library Values**
118192

119193
If you are building a [FlutterFlow Library](../../resources/projects/libraries.md) and need to include API keys in native code without exposing them when users import the library, you can use [Library Values](../../resources/projects/libraries.md#library-values) as placeholders. This ensures that when someone installs your library, they can define their own values without seeing the actual key or credentials inside the native files.
@@ -130,6 +204,9 @@ For example, If your library requires an API key for a third-party service (e.g.
130204

131205
The library user will define their own API key under Library Values when importing your library. At build time, FlutterFlow replaces `{{MAPS_API_KEY}}` with the user-defined key.
132206

207+
![lib-values-in-native-code-example-1](imgs/lib-values-in-native-code-example-1.avif)
208+
209+
133210
## Editable Files
134211

135212
FlutterFlow allows editing several key native files. Below, we cover each file’s role, why you might need to edit it, and examples of real-world use cases.
@@ -356,7 +433,7 @@ Here are some scenarios where you may need to modify the `main.dart` file:
356433

357434
Many packages have initialization calls. For example, if you added a custom package for analytics or error tracking (say Sentry or a logging service), you might need to call `SentryFlutter.init()` or set up an error handler at app startup. By placing that call in `main.dart` (before or right after `runApp`), you ensure it’s executed early.
358435

359-
```dart
436+
```jsx
360437
import 'dart:async';
361438

362439
import 'package:flutter/widgets.dart';
@@ -383,7 +460,7 @@ This ensures Sentry is ready before the app starts, just like Firebase initializ
383460

384461
If you want to change the status bar color and adjust icon brightness for Android and iOS, you need to modify `main.dart` before calling `runApp()`.
385462

386-
```dart
463+
```jsx
387464

388465
import 'package:flutter/services.dart';
389466

@@ -405,7 +482,7 @@ void main() {
405482

406483
Some apps require landscape-only or portrait-only modes. You can enforce screen orientation in `main.dart` before launching the app.
407484

408-
```dart
485+
```jsx
409486
import 'package:flutter/services.dart';
410487

411488
Future<void> main() async {
@@ -426,7 +503,7 @@ This ensures the app only runs in landscape mode.
426503

427504
If your app needs to respond to lifecycle events, such as tracking when the app goes into the background or returns to the foreground, you can attach an observer.
428505

429-
```dart
506+
```jsx
430507
import 'package:flutter/widgets.dart';
431508

432509
void main() {
@@ -459,7 +536,7 @@ Here are some scenarios where you may need to modify the ProGuard file:
459536

460537
ProGuard can obfuscate critical libraries, breaking their functionality. To prevent this, you need to keep specific classes used by the library.
461538

462-
```
539+
```jsx
463540
# Firebase
464541
-keep class com.google.firebase.** { *; }
465542

@@ -474,7 +551,7 @@ This ensures that Firebase and Gson classes are not obfuscated, preventing seria
474551

475552
If your app crashes in release mode but works in debug mode, ProGuard might be removing important classes. To troubleshoot, you can add logging and keep rules.
476553

477-
```
554+
```jsx
478555
-assumenosideeffects class android.util.Log {
479556
public static *** d(...);
480557
public static *** v(...);
@@ -488,7 +565,7 @@ This removes debug logs in release builds but retains them for troubleshooting.
488565

489566
Attackers can decompile APKs and view sensitive debug logs. To remove these debug logs, add:
490567

491-
```
568+
```jsx
492569
-dontwarn android.util.Log
493570
```
494571

@@ -497,7 +574,7 @@ Attackers can decompile APKs and view sensitive debug logs. To remove these debu
497574

498575
If your app uses native C/C++ libraries (JNI), ProGuard may mistakenly remove required components. To prevent this:
499576

500-
```
577+
```jsx
501578
-keep class com.example.native.** { *; }
502579
-keepclassmembers class * {
503580
native <methods>;
@@ -510,7 +587,7 @@ This keeps all native methods intact.
510587

511588
Some libraries rely on reflection to dynamically call methods, which ProGuard may remove.
512589

513-
```
590+
```jsx
514591
-keep class * implements android.os.Parcelable { *; }
515592
-keepclassmembers class ** {
516593
@android.webkit.JavascriptInterface <methods>;

0 commit comments

Comments
 (0)