feat : apk updater

This commit is contained in:
2025-06-07 14:54:44 +03:30
parent 208eae5487
commit 40b8d6f913
7 changed files with 143 additions and 19 deletions

View File

@@ -26,6 +26,12 @@ android {
versionName = flutter.versionName
}
packaging {
resources {
excludes += "META-INF/DEPENDENCIES"
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("debug")

View File

@@ -1,33 +1,37 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
android:label="رصــدیـار"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
android:icon="@mipmap/launcher_icon"
android:label="رصــدیـار">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:enableOnBackInvokedCallback="true"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:enableOnBackInvokedCallback="true"
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. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<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.
@@ -35,6 +39,16 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
@@ -43,8 +57,8 @@
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>

View File

@@ -1,5 +1,57 @@
package هir.mnpc.rasadyar
package ir.mnpc.rasadyar
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import androidx.core.content.FileProvider
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File
class MainActivity : FlutterActivity()
class MainActivity : FlutterActivity() {
private val CHANNEL = "apk_installer"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
CHANNEL
).setMethodCallHandler { call, result ->
if (call.method == "installApk") {
val apkPath = call.argument<String>("appPath") ?: ""
installApk(apkPath)
result.success(null)
}
}
}
private fun installApk(path: String) {
val file = File(path)
val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val apkUri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val uri = FileProvider.getUriForFile(
applicationContext,
"${BuildConfig.APPLICATION_ID}.fileprovider",
file
)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
uri
} else {
Uri.fromFile(file)
}
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
applicationContext.startActivity(intent)
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
</paths>

View File

@@ -10,18 +10,18 @@ export 'package:flutter_secure_storage/flutter_secure_storage.dart';
export 'package:flutter_slidable/flutter_slidable.dart';
export 'package:font_awesome_flutter/font_awesome_flutter.dart';
export 'package:device_info_plus/device_info_plus.dart';
export 'package:dio/dio.dart' show DioException;
export 'package:dio/dio.dart' ;
export 'package:pretty_dio_logger/pretty_dio_logger.dart';
//freezed
export 'package:freezed_annotation/freezed_annotation.dart';
export 'package:geolocator/geolocator.dart';
export 'package:get/get.dart';
export 'package:get/get.dart' hide FormData, MultipartFile, Response;
//di
export 'package:get_it/get_it.dart';
export 'injection/di.dart';
//local storage
export 'package:hive_ce_flutter/hive_flutter.dart';
export 'package:flutter_secure_storage/flutter_secure_storage.dart';
export 'infrastructure/local/hive_local_storage.dart';
//encryption

View File

@@ -0,0 +1,22 @@
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
class ApkUpdater {
static const _channel = MethodChannel('apk_installer');
static Future<void> downloadAndInstall() async {
final dio = Dio();
final apkUrl = "https://yourdomain.com/app.apk";
final dir = await getExternalStorageDirectory();
final path = "${dir!.path}/update.apk";
final file = File(path);
await dio.download(apkUrl, path);
await _channel.invokeMethod("installApk", {"path": path});
}
}

View File

@@ -233,6 +233,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.0"
device_info_plus:
dependency: transitive
description:
name: device_info_plus
sha256: "0c6396126421b590089447154c5f98a5de423b70cfb15b1578fd018843ee6f53"
url: "https://pub.dev"
source: hosted
version: "11.4.0"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2"
url: "https://pub.dev"
source: hosted
version: "7.0.2"
dio:
dependency: transitive
description:
@@ -1277,6 +1293,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.13.0"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
wkt_parser:
dependency: transitive
description: