Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,16 @@ android {
signingConfig = signingConfigs.getByName("debug")
}
}

dynamicFeatures += setOf(":code_asset_module", ":asset_only_module")
}

flutter {
source = "../.."
}

dependencies {
implementation("com.google.android.play:core:1.10.3")
}


4 changes: 2 additions & 2 deletions android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
47 changes: 27 additions & 20 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,45 +1,52 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application
android:label="test_dynamic_module"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:name="io.flutter.embedding.android.FlutterPlayStoreSplitApplication"
android:icon="@mipmap/ic_launcher"
android:label="test_dynamic_module">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
android:name="io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping"
android:value="2:" />

<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data
android:name="io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping"
android:value="2:code_asset_module" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
<action android:name="android.intent.action.PROCESS_TEXT" />
<data android:mimeType="text/plain" />
</intent>
</queries>
</manifest>
</manifest>
5 changes: 5 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="code_asset_moduleName">code_asset_module</string>
<string name="asset_only_moduleName">asset_only_module</string>
</resources>
44 changes: 44 additions & 0 deletions android/asset_only_module/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader("UTF-8") { reader ->
localProperties.load(reader)
}
}

def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) {
flutterVersionCode = "1"
}

def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0"
}

apply plugin: "com.android.dynamic-feature"

android {
namespace = "com.example.test_dynamic_module.asset_only_module"
compileSdk = 35

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

sourceSets {
applicationVariants.all { variant ->
main.assets.srcDirs += "${project.layout.buildDirectory}/intermediates/flutter/${variant.name}/deferred_assets"
main.jniLibs.srcDirs += "${project.layout.buildDirectory}/intermediates/flutter/${variant.name}/deferred_libs"
}
}

defaultConfig {
minSdk 24
}
}

dependencies {
implementation(project(":app"))
}
12 changes: 12 additions & 0 deletions android/asset_only_module/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution">

<dist:module
dist:instant="false"
dist:title="@string/asset_only_moduleName">
<dist:delivery>
<dist:on-demand />
</dist:delivery>
<dist:fusing dist:include="true" />
</dist:module>
</manifest>
34 changes: 34 additions & 0 deletions android/code_asset_module/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader("UTF-8") { reader ->
localProperties.load(reader)
}
}

apply plugin: "com.android.dynamic-feature"

android {
namespace = "com.example.test_dynamic_module.code_asset_module"
compileSdk = 35

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

sourceSets {
applicationVariants.all { variant ->
main.assets.srcDirs += "${project.layout.buildDirectory}/intermediates/flutter/${variant.name}/deferred_assets"
main.jniLibs.srcDirs += "${project.layout.buildDirectory}/intermediates/flutter/${variant.name}/deferred_libs"
}
}

defaultConfig {
minSdk 24
}
}

dependencies {
implementation(project(":app"))
}
12 changes: 12 additions & 0 deletions android/code_asset_module/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution">

<dist:module
dist:instant="false"
dist:title="@string/code_asset_moduleName">
<dist:delivery>
<dist:on-demand />
</dist:delivery>
<dist:fusing dist:include="true" />
</dist:module>
</manifest>
2 changes: 2 additions & 0 deletions android/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ plugins {
}

include(":app")
include(":code_asset_module")
include(":asset_only_module")
Binary file added assets/images/image1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/image2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added assets/images/image3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/image4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/image5.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/image6.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/image7.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/image8.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/videos/music.mp4
Binary file not shown.
1 change: 1 addition & 0 deletions ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
1 change: 1 addition & 0 deletions ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
125 changes: 125 additions & 0 deletions lib/home_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

// import deferred module
import 'images_page_view.dart';
import 'modules/code_asset_module/code_asset_module.dart'
deferred as code_asset_module;

class HomeView extends StatefulWidget {
const HomeView({super.key});

@override
State<HomeView> createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
bool _isLoading = false; // trạng thái đang tải module
String _loadingMessage = '';

Future<void> _loadCodeAssetModule() async {
try {
setState(() {
_isLoading = true;
_loadingMessage = 'Đang tải module Code + Asset...';
});

// Gọi loadLibrary()
await code_asset_module.loadLibrary();

setState(() {
_isLoading = false;
_loadingMessage = '';
});

// Navigate sang VideoView trong module đã load
if (mounted) {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => code_asset_module.VideoView()),
);
}
} catch (e, s) {
if (kDebugMode) {
print('Lỗi khi tải module: $e\n$s');
}
setState(() {
_isLoading = false;
_loadingMessage = 'Tải module thất bại!';
});
}
}

@override
Widget build(BuildContext context) {
return Stack(
children: [
Scaffold(
appBar: AppBar(title: const Text('Demo Deferred Component Flutter')),
body: Column(
children: [
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: _buildModuleItem(
'Module Code + Asset',
_loadCodeAssetModule,
),
),
Flexible(
child: _buildModuleItem('Module Asset', () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const ImagesPageView(),
),
);
}),
),
],
),
),
],
),
),

// Overlay loading
if (_isLoading)
Container(
color: Colors.black54,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(color: Colors.white),
const SizedBox(height: 16),
Text(
_loadingMessage,
style: const TextStyle(color: Colors.white, fontSize: 16),
),
],
),
),
),
],
);
}

Widget _buildModuleItem(String title, VoidCallback onPressed) {
return GestureDetector(
onTap: onPressed,
child: Container(
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(8),
),
child: Text(
title,
style: const TextStyle(color: Colors.white, fontSize: 18),
),
),
);
}
}
Loading