package_flutter_env 0.0.6+1
package_flutter_env: ^0.0.6+1 copied to clipboard
Using MIAppBarWidget to create a custom app bar.
Custom script for generating environment-specific code for different platforms #
Features #
The flutter_env.dart file appears to be a custom script for generating environment-specific code for different platforms (Dart, Objective-C, and Gradle for Android). It reads from an environment file (.env by default), and generates code based on the key-value pairs in the environment file.
Here's a basic usage guide:
- Create an environment file: Create a .env file in your project root (or specify a different file using the envfile argument). This file should contain key-value pairs, one per line, like this:
API_KEY=123456
BASE_URL=https://api.example.com
2.Run the script: You can run the DotENV class with the command-line arguments. For example:
void main(List<String> args) {
DotENV(args);
}
You can pass arguments to specify the platform (platform), the environment file (envfile), and the directory name (dirname). If not specified, it will use default values.
3.Generated code: The script will generate a Dart file (lib/env.dart by default) with a class ENV that contains static string properties for each key-value pair in the environment file. For example:
class ENV {
static String API_KEY = "123456";
static String BASE_URL = "https://api.example.com";
}
You can then import this file in your Flutter code and access the environment variables like this: ENV.API_KEY.
Please note that this is a basic guide and the actual usage may vary depending on your project setup and requirements. Also, remember to exclude your environment files from version control to avoid committing sensitive data.
Unit Test Command #
At the root of the project, run the following command:
flutter test test/dotenv_test.dart
Generate the env.dart file #
At the root of the example project, run the following command:
like: /Users/danli/Desktop/2024/packages/package_flutter_env/example
Because test is the development environment, the generated file is in the lib folder.
flutter test test/env_test.dart
import os
native_extensions = (".c", ".cpp", ".cc", ".cxx", ".h", ".hpp")
build_files = ("CMakeLists.txt", "Android.mk")
def has_native_code(root_dir):
native_files = []
for root, dirs, files in os.walk(root_dir):
for file in files:
if file.endswith(native_extensions) or file in build_files:
native_files.append(os.path.join(root, file))
return native_files
if __name__ == "__main__":
project_root = os.getcwd()
android_dir = os.path.join(project_root, "android")
plugins_dir = os.path.join(project_root, "plugins")
results = []
if os.path.exists(android_dir):
results.extend(has_native_code(android_dir))
if os.path.exists(plugins_dir):
results.extend(has_native_code(plugins_dir))
if results:
print("⚠️ 检测到以下原生代码/构建文件:")
for f in results:
print(" -", f)
print("\n👉 升级 NDK 可能会影响这些代码或依赖的插件,请重点测试。")
else:
print("✅ 未检测到原生代码文件,NDK 升级影响较小。")
// pubspec.yaml dependencies:
// dependencies:
// security_plus: ^3.0.1
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:security_plus/security_plus.dart';
import 'dart:io';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Security Plus Demo',
home: SecurityCheckScreen(),
);
}
}
class SecurityCheckScreen extends StatefulWidget {
@override
_SecurityCheckScreenState createState() => _SecurityCheckScreenState();
}
class _SecurityCheckScreenState extends State<SecurityCheckScreen> {
bool _isLoading = true;
bool _isSecure = true;
Map<String, bool> _securityStatus = {};
String _errorMessage = '';
@override
void initState() {
super.initState();
_performSecurityChecks();
}
Future<void> _performSecurityChecks() async {
try {
// Perform all security checks (excluding mock location)
final results = await Future.wait([
_checkRoot(),
_checkEmulator(),
_checkDevelopmentMode(),
_checkExternalStorage(),
]);
final securityStatus = {
'Root Detection': results[0],
'Emulator Detection': results[1],
'Development Mode': results[2],
'External Storage': results[3],
};
// Check if device is secure (all checks should be false for secure device)
bool isSecure = !securityStatus.values.any((status) => status == true);
setState(() {
_securityStatus = securityStatus;
_isSecure = isSecure;
_isLoading = false;
});
if (!isSecure) {
_showSecurityAlert();
}
} catch (e) {
setState(() {
_errorMessage = 'Security check failed: $e';
_isLoading = false;
});
}
}
Future<bool> _checkRoot() async {
try {
return await SecurityPlus.isRooted;
} catch (e) {
print('Root check error: $e');
return false;
}
}
Future<bool> _checkEmulator() async {
try {
return await SecurityPlus.isEmulator;
} catch (e) {
print('Emulator check error: $e');
return false;
}
}
Future<bool> _checkDevelopmentMode() async {
try {
return await SecurityPlus.isDevelopmentModeEnable;
} catch (e) {
print('Development mode check error: $e');
return false;
}
}
Future<bool> _checkMockLocation() async {
// Mock location check removed - requires location permission
return false;
}
Future<bool> _checkExternalStorage() async {
try {
return await SecurityPlus.isOnExternalStorage;
} catch (e) {
print('External storage check error: $e');
return false;
}
}
void _showSecurityAlert() {
List<String> threats = [];
_securityStatus.forEach((key, value) {
if (value) threats.add(key);
});
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Row(
children: [
Icon(Icons.warning, color: Colors.red),
SizedBox(width: 8),
Text('Security Alert'),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Security threats detected:'),
SizedBox(height: 8),
...threats.map((threat) => Text('• $threat',
style: TextStyle(color: Colors.red))),
SizedBox(height: 16),
Text('This app may not function properly on compromised devices.'),
],
),
actions: [
TextButton(
onPressed: () => SystemNavigator.pop(),
child: Text('Exit App'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
// You might want to continue with limited functionality
},
child: Text('Continue Anyway'),
),
],
),
);
}
Widget _buildSecurityStatusCard(String title, bool status) {
return Card(
child: ListTile(
leading: Icon(
status ? Icons.warning : Icons.check_circle,
color: status ? Colors.red : Colors.green,
),
title: Text(title),
subtitle: Text(status ? 'Threat Detected' : 'Secure'),
trailing: status ?
Icon(Icons.error_outline, color: Colors.red) :
Icon(Icons.security, color: Colors.green),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Security Plus Demo'),
backgroundColor: _isSecure ? Colors.green : Colors.red,
),
body: _isLoading
? Center(child: CircularProgressIndicator())
: _errorMessage.isNotEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error, size: 64, color: Colors.red),
SizedBox(height: 16),
Text(_errorMessage, textAlign: TextAlign.center),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
setState(() {
_isLoading = true;
_errorMessage = '';
});
_performSecurityChecks();
},
child: Text('Retry'),
),
],
),
)
: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
// Overall Security Status
Container(
width: double.infinity,
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: _isSecure ? Colors.green[100] : Colors.red[100],
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: _isSecure ? Colors.green : Colors.red,
),
),
child: Column(
children: [
Icon(
_isSecure ? Icons.security : Icons.warning,
size: 48,
color: _isSecure ? Colors.green : Colors.red,
),
SizedBox(height: 8),
Text(
_isSecure ? 'Device is Secure' : 'Security Threats Detected',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: _isSecure ? Colors.green[800] : Colors.red[800],
),
),
],
),
),
SizedBox(height: 24),
// Individual Security Checks
Text(
'Security Check Results',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
SizedBox(height: 16),
Expanded(
child: ListView(
children: _securityStatus.entries
.map((entry) => _buildSecurityStatusCard(entry.key, entry.value))
.toList(),
),
),
// Refresh Button
SizedBox(height: 16),
ElevatedButton.icon(
onPressed: () {
setState(() {
_isLoading = true;
});
_performSecurityChecks();
},
icon: Icon(Icons.refresh),
label: Text('Refresh Security Check'),
),
],
),
),
);
}
}
// Advanced Security Service Class
class SecurityService {
static Future<SecurityCheckResult> performComprehensiveCheck() async {
try {
// Perform all checks (excluding mock location)
final results = await Future.wait([
SecurityPlus.isRooted,
SecurityPlus.isEmulator,
SecurityPlus.isDevelopmentModeEnable,
SecurityPlus.isOnExternalStorage,
]);
return SecurityCheckResult(
isRooted: results[0],
isEmulator: results[1],
isDevelopmentMode: results[2],
isMockLocation: false, // Disabled
isOnExternalStorage: results[3],
);
} catch (e) {
throw SecurityCheckException('Failed to perform security checks: $e');
}
}
static Future<bool> isDeviceSecure() async {
try {
final result = await performComprehensiveCheck();
return !result.hasAnyThreats();
} catch (e) {
// In case of error, assume device is not secure
return false;
}
}
}
// Data Models
class SecurityCheckResult {
final bool isRooted;
final bool isEmulator;
final bool isDevelopmentMode;
final bool isMockLocation;
final bool isOnExternalStorage;
SecurityCheckResult({
required this.isRooted,
required this.isEmulator,
required this.isDevelopmentMode,
required this.isMockLocation,
required this.isOnExternalStorage,
});
bool hasAnyThreats() {
return isRooted || isEmulator || isDevelopmentMode || isOnExternalStorage;
}
List<String> getThreats() {
List<String> threats = [];
if (isRooted) threats.add('Device is rooted/jailbroken');
if (isEmulator) threats.add('Running on emulator');
if (isDevelopmentMode) threats.add('Development mode enabled');
if (isOnExternalStorage) threats.add('App running from external storage');
return threats;
}
}
class SecurityCheckException implements Exception {
final String message;
SecurityCheckException(this.message);
@override
String toString() => 'SecurityCheckException: $message';
}