Added proper p-256 key generation at app first launch and in settings
All checks were successful
/ mirror (push) Successful in 5s
/ deploy (push) Successful in 36s

This commit is contained in:
stcb 2025-02-13 15:35:18 +02:00
parent d754ba5935
commit 985fd06b56
141 changed files with 258 additions and 3220 deletions

4
.gitignore vendored
View File

@ -181,4 +181,6 @@ app.*.symbols
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
!.vscode/settings.json
!.vscode/settings.json
dialer/android/gradle.properties
.gitignore

View File

@ -1,4 +1,4 @@
package com.example.keystore
package com.icing.dialer
import java.security.KeyStore

View File

@ -1,4 +1,4 @@
package com.example.keystore
package com.icing.dialer
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties

View File

@ -1,5 +1,6 @@
package com.example.yourapp.services.cryptography.platform.android
package com.icing.dialer
import java.security.PrivateKey
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64

View File

@ -1,5 +1,19 @@
package com.icing.dialer
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import com.icing.dialer.KeystoreHelper
class MainActivity: FlutterActivity()
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.keystore"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
// Delegate method calls to KeystoreHelper
KeystoreHelper(call, result).handleMethodCall()
}
}
}

View File

@ -1,4 +1,4 @@
package com.example.keystore
package com.icing.dialer
import java.security.KeyStore
import java.security.PublicKey

View File

@ -1,9 +1,10 @@
package com.example.keystore
package com.icing.dialer
import android.security.keystore.KeyProperties
import java.security.KeyStore
import java.security.Signature
import android.util.Base64
import java.security.PrivateKey
object SignerHelper {
@ -21,7 +22,7 @@ object SignerHelper {
try {
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply { load(null) }
val privateKey = keyStore.getKey(alias, null) ?: throw Exception("Private key not found for alias \"$alias\".")
val privateKey = keyStore.getKey(alias, null) as? PrivateKey?: throw Exception("Private key not found for alias \"$alias\".")
val signature = Signature.getInstance("SHA256withECDSA")
signature.initSign(privateKey)

View File

@ -1,19 +0,0 @@
package com.example.yourapp
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import com.icingDialer.KeystoreHelper
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.keystore"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
// Delegate method calls to KeystoreHelper
KeystoreHelper(call, result).handleMethodCall()
}
}
}

View File

@ -2,3 +2,4 @@ org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryErro
android.useAndroidX=true
android.enableJetifier=true
dev.steenbakker.mobile_scanner.useUnbundled=true
org.gradle.java.home=/usr/lib/jvm/java-17-openjdk-amd64

View File

@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

View File

@ -1,64 +0,0 @@
// import 'package:flutter/material.dart';
//
// class DeleteKeyPairPage extends StatelessWidget {
// const DeleteKeyPairPage({super.key});
//
// Future<void> _deleteKeyPair(BuildContext context) async {
// final keyStorage = KeyStorage();
// await keyStorage.deleteKeys();
//
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(
// content: Text('The key pair has been deleted.'),
// ),
// );
//
// Navigator.pop(context);
// }
//
// void _showConfirmationDialog(BuildContext context) {
// showDialog(
// context: context,
// builder: (BuildContext context) {
// return AlertDialog(
// title: const Text('Confirm Deletion'),
// content: const Text(
// 'Are you sure you want to delete the cryptography pair? This action is irreversible.'),
// actions: [
// TextButton(
// child: const Text('Cancel'),
// onPressed: () {
// Navigator.of(context).pop();
// },
// ),
// TextButton(
// child: const Text('Delete'),
// onPressed: () {
// Navigator.of(context).pop();
// _deleteKeyPair(context);
// },
// ),
// ],
// );
// },
// );
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// backgroundColor: Colors.black,
// appBar: AppBar(
// title: const Text('Delete a Key Pair'),
// ),
// body: Center(
// child: ElevatedButton(
// onPressed: () {
// _showConfirmationDialog(context);
// },
// child: const Text('Delete Key Pair'),
// ),
// ),
// );
// }
// }

View File

@ -1,40 +0,0 @@
// import 'package:flutter/material.dart';
// import 'package:dialer/services/cryptography/asymmetric_crypto_service.dart';
// import 'dart:math';
//
// class GenerateNewKeyPairPage extends StatelessWidget {
// const GenerateNewKeyPairPage({super.key});
//
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// backgroundColor: Colors.black,
// appBar: AppBar(
// title: const Text('Generate a New Key Pair'),
// ),
// body: Center(
// child: ElevatedButton(
// onPressed: () async {
// var keyName = Random().nextInt(10000000).toString();
// await AsymmetricCryptoService().generateKeyPair(keyName);
// showDialog(
// context: context,
// builder: (context) => AlertDialog(
// title: const Text('Keys Generated (${keyName})'),
// content: const Text('The new key pair has been generated and stored securely.'),
// actions: [
// TextButton(
// onPressed: () => Navigator.pop(context),
// child: const Text('OK'),
// ),
// ],
// ),
// );
// },
// child: const Text('Generate a New Key Pair'),
// ),
// ),
// );
// }
// }

View File

@ -0,0 +1,145 @@
import 'package:flutter/material.dart';
import 'package:dialer/services/cryptography/asymmetric_crypto_service.dart';
class ManageKeysPage extends StatefulWidget {
const ManageKeysPage({Key? key}) : super(key: key);
@override
_ManageKeysPageState createState() => _ManageKeysPageState();
}
class _ManageKeysPageState extends State<ManageKeysPage> {
final AsymmetricCryptoService _cryptoService = AsymmetricCryptoService();
List<Map<String, dynamic>> _keys = [];
bool _isLoading = false;
@override
void initState() {
super.initState();
_loadKeys();
}
Future<void> _loadKeys() async {
setState(() {
_isLoading = true;
});
try {
List<Map<String, dynamic>> keys = await _cryptoService.getAllKeys();
setState(() {
_keys = keys;
});
} catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Error loading keys: $e')));
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _generateKey() async {
setState(() {
_isLoading = true;
});
try {
await _cryptoService.generateKeyPair();
await _loadKeys();
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Key generated successfully')));
} catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Error generating key: $e')));
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _deleteKey(String alias) async {
setState(() {
_isLoading = true;
});
try {
await _cryptoService.deleteKeyPair(alias);
await _loadKeys();
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Key deleted successfully')));
} catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Error deleting key: $e')));
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _viewPublicKey(String alias) async {
try {
final publicKey = await _cryptoService.getPublicKey(alias);
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text('Public Key'),
content: SingleChildScrollView(child: Text(publicKey)),
actions: [
TextButton(
child: const Text('Close'),
onPressed: () {
Navigator.pop(context);
},
)
],
),
);
} catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Error retrieving public key: $e')));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Manage Keys'),
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: _keys.isEmpty
? const Center(child: Text('No keys found'))
: ListView.builder(
itemCount: _keys.length,
itemBuilder: (context, index) {
final keyData = _keys[index];
return ListTile(
title: Text(keyData['label'] ?? 'No label'),
subtitle: Text(keyData['alias'] ?? ''),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.visibility),
tooltip: 'View Public Key',
onPressed: () => _viewPublicKey(keyData['alias']),
),
IconButton(
icon: const Icon(Icons.delete),
tooltip: 'Delete Key',
onPressed: () => _deleteKey(keyData['alias']),
),
],
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _generateKey,
child: const Icon(Icons.add),
tooltip: 'Generate New Key',
),
);
}
}

View File

@ -1,249 +0,0 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
import 'package:dialer/services/cryptography/asymmetric_crypto_service.dart';
class ManageKeysPage extends StatefulWidget {
@override
_ManageKeysPageState createState() => _ManageKeysPageState();
}
class _ManageKeysPageState extends State<ManageKeysPage> {
List<Map<String, dynamic>> _keys = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
_fetchKeys();
}
Future<void> _fetchKeys() async {
final AsymmetricCryptoService cryptoService = Provider.of<AsymmetricCryptoService>(context, listen: false);
try {
final keys = await cryptoService.getAllKeys();
setState(() {
_keys = keys;
_isLoading = false;
});
} catch (e) {
// Handle error, e.g., show a snackbar
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error fetching keys: $e')),
);
}
}
Future<void> _createKey() async {
final AsymmetricCryptoService cryptoService = Provider.of<AsymmetricCryptoService>(context, listen: false);
String? label = await _showCreateKeyDialog();
if (label == null) return; // User cancelled
try {
await cryptoService.generateKeyPair(label: label);
await _fetchKeys();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Key "$label" created successfully.')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error creating key: $e')),
);
}
}
Future<String?> _showCreateKeyDialog() async {
String label = '';
return showDialog<String>(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Create New Key'),
content: TextField(
onChanged: (value) {
label = value;
},
decoration: InputDecoration(hintText: "Enter key label"),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(null),
child: Text('Cancel'),
),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(label.trim().isEmpty ? 'Key ${Uuid().v4()}' : label.trim()),
child: Text('Create'),
),
],
);
},
);
}
Future<void> _deleteKey(String alias, String label) async {
final AsymmetricCryptoService cryptoService = Provider.of<AsymmetricCryptoService>(context, listen: false);
bool confirm = await _showDeleteConfirmationDialog(label);
if (!confirm) return;
try {
await cryptoService.deleteKeyPair(alias);
await _fetchKeys();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Key "$label" deleted successfully.')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error deleting key: $e')),
);
}
}
Future<bool> _showDeleteConfirmationDialog(String label) async {
return await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text('Delete Key'),
content: Text('Are you sure you want to delete the key "$label"? This action cannot be undone.'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text('Cancel'),
),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(true),
style: ElevatedButton.styleFrom(foregroundColor: Colors.red),
child: Text('Delete'),
),
],
),
) ??
false;
}
Future<void> _viewPublicKey(String alias, String label) async {
final AsymmetricCryptoService cryptoService = Provider.of<AsymmetricCryptoService>(context, listen: false);
try {
final String publicKey = await cryptoService.getPublicKey(alias);
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Public Key for "$label"'),
content: SelectableText(publicKey),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Close'),
),
// Optionally, add a button to copy the key to clipboard
],
),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error retrieving public key: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Manage Keys'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: _createKey,
tooltip: 'Create New Key',
),
],
),
body: _isLoading
? Center(child: CircularProgressIndicator())
: _keys.isEmpty
? Center(child: Text('No keys found.'))
: ListView.builder(
itemCount: _keys.length,
itemBuilder: (context, index) {
final key = _keys[index];
return ListTile(
title: Text(key['label']),
subtitle: Text('Created at: ${key['created_at']}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.edit),
onPressed: () => _editKeyLabel(key['alias'], key['label']),
tooltip: 'Edit Label',
),
IconButton(
icon: Icon(Icons.visibility),
onPressed: () => _viewPublicKey(key['alias'], key['label']),
tooltip: 'View Public Key',
),
IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () => _deleteKey(key['alias'], key['label']),
tooltip: 'Delete Key',
),
],
),
);
},
));
}
/// Updates the label of a key.
Future<void> _editKeyLabel(String alias, String currentLabel) async {
final AsymmetricCryptoService cryptoService = Provider.of<AsymmetricCryptoService>(context, listen: false);
String? newLabel = await _showEditLabelDialog(currentLabel);
if (newLabel == null) return; // User cancelled
try {
await cryptoService.updateKeyLabel(alias, newLabel);
await _fetchKeys();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Key label updated to "$newLabel".')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error updating key label: $e')),
);
}
}
Future<String?> _showEditLabelDialog(String currentLabel) async {
String label = currentLabel;
return showDialog<String>(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Edit Key Label'),
content: TextField(
onChanged: (value) {
label = value;
},
decoration: InputDecoration(hintText: "Enter new key label"),
controller: TextEditingController(text: currentLabel),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(null),
child: Text('Cancel'),
),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(label.trim().isEmpty ? currentLabel : label.trim()),
child: Text('Save'),
),
],
);
},
);
}
}

View File

@ -1,49 +0,0 @@
// import 'package:flutter/material.dart';
// import 'package:pretty_qr_code/pretty_qr_code.dart';
// import 'widgets/key_storage.dart';
//
// class DisplayPublicKeyQRCodePage extends StatelessWidget {
// const DisplayPublicKeyQRCodePage({super.key});
//
// Future<String?> _loadPublicKey() async {
// final keyStorage = KeyStorage();
// return keyStorage.getPublicKey();
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// backgroundColor: Colors.black,
// appBar: AppBar(
// title: const Text('Public Key in QR Code'),
// ),
// body: FutureBuilder<String?>(
// future: _loadPublicKey(),
// builder: (context, snapshot) {
// if (snapshot.connectionState == ConnectionState.waiting) {
// return const Center(child: CircularProgressIndicator());
// }
//
// final publicKey = snapshot.data;
// if (publicKey == null) {
// return const Center(
// child: Text(
// 'No public key found.',
// style: TextStyle(color: Colors.white),
// ),
// );
// }
//
// return Center(
// child: PrettyQr(
// data: publicKey,
// size: 250,
// roundEdges: true,
// elementColor: Colors.white,
// ),
// );
// },
// ),
// );
// }
// }

View File

@ -1,50 +0,0 @@
// import 'package:flutter/material.dart';
// import 'widgets/key_storage.dart';
//
// class DisplayPublicKeyTextPage extends StatelessWidget {
// const DisplayPublicKeyTextPage({super.key});
//
// Future<String?> _loadPublicKey() async {
// final keyStorage = KeyStorage();
// return await keyStorage.getPublicKey();
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// backgroundColor: Colors.black,
// appBar: AppBar(
// title: const Text('Public Key as Text'),
// ),
// body: FutureBuilder<String?>(
// future: _loadPublicKey(),
// builder: (context, snapshot) {
// if (snapshot.connectionState == ConnectionState.waiting) {
// return const Center(child: CircularProgressIndicator());
// }
//
// final publicKey = snapshot.data;
// if (publicKey == null) {
// return const Center(
// child: Text(
// 'No public key found.',
// style: TextStyle(color: Colors.white),
// ),
// );
// }
//
// return Center(
// child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: SelectableText(
// publicKey,
// style: const TextStyle(color: Colors.white),
// textAlign: TextAlign.center,
// ),
// ),
// );
// },
// ),
// );
// }
// }

View File

@ -2,11 +2,9 @@
import 'package:flutter/material.dart';
import 'package:dialer/features/settings/call/settingsCall.dart';
import 'package:dialer/features/settings/sim/settings_accounts.dart';
// import 'package:dialer/features/settings/cryptography/';
import 'package:dialer/features/settings/blocked/settings_blocked.dart';
import 'cryptography/manage_keys_page.dart';
import 'cryptography/key_management.dart';
class SettingsPage extends StatelessWidget {
const SettingsPage({super.key});
@ -19,13 +17,7 @@ class SettingsPage extends StatelessWidget {
MaterialPageRoute(builder: (context) => const SettingsCallPage()),
);
break;
case 'Sim settings':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SettingsAccountsPage()),
);
break;
case 'Cryptography':
case 'Key management':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ManageKeysPage()),
@ -48,7 +40,6 @@ class SettingsPage extends StatelessWidget {
Widget build(BuildContext context) {
final settingsOptions = [
'Calling settings',
'Page of telephone accounts',
'Key management',
'Blocked numbers'
];

View File

@ -1,91 +0,0 @@
import 'package:flutter/material.dart';
import 'package:mobile_number/mobile_number.dart';
class ChooseSimPage extends StatefulWidget {
const ChooseSimPage({Key? key}) : super(key: key);
@override
_ChooseSimPageState createState() => _ChooseSimPageState();
}
class _ChooseSimPageState extends State<ChooseSimPage> {
List<SimCard> _simCards = [];
int? _selectedSimIndex;
@override
void initState() {
super.initState();
_fetchSimCards();
}
Future<void> _fetchSimCards() async {
try {
bool permissionsGranted = await MobileNumber.hasPhonePermission;
if (!permissionsGranted) {
await MobileNumber.requestPhonePermission;
permissionsGranted = await MobileNumber.hasPhonePermission;
}
if (permissionsGranted) {
List<SimCard>? simCards = await MobileNumber.getSimCards;
if (simCards != null && mounted) {
setState(() {
_simCards = simCards;
_selectedSimIndex = 0;
});
} else {
print('No SIM cards found');
}
} else {
print('Phone permission denied');
}
} catch (e) {
print('Failed to get SIM cards: $e');
}
}
void _onSimSelected(int? index) {
if (index != null) {
setState(() {
_selectedSimIndex = index;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Choose SIM'),
),
body: _simCards.isEmpty
? const Center(
child: Text(
'No SIM cards found',
style: TextStyle(color: Colors.white),
),
)
: ListView.builder(
itemCount: _simCards.length,
itemBuilder: (context, index) {
final sim = _simCards[index];
return ListTile(
title: Text(
'SIM ${index + 1}',
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
'Operator: ${sim.carrierName ?? 'N/A'}',
style: const TextStyle(color: Colors.grey),
),
trailing: Radio<int>(
value: index,
groupValue: _selectedSimIndex,
onChanged: _onSimSelected,
),
);
},
),
);
}
}

View File

@ -1,57 +0,0 @@
import 'package:flutter/material.dart';
import 'choose_sim.dart';
import 'sim_parameters.dart';
class SettingsAccountsPage extends StatelessWidget {
const SettingsAccountsPage({super.key});
void _navigateToAccountOption(BuildContext context, String option) {
switch (option) {
case 'Chose SIM card':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ChooseSimPage()),
);
break;
case 'SIM card parameters':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SimParametersPage()),
);
break;
default:
break;
}
}
@override
Widget build(BuildContext context) {
final accountOptions = [
'Chose SIM card',
'SIM card parameters',
];
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Sim settings'),
),
body: ListView.builder(
itemCount: accountOptions.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
accountOptions[index],
style: const TextStyle(color: Colors.white),
),
trailing:
const Icon(Icons.arrow_forward_ios, color: Colors.white),
onTap: () {
_navigateToAccountOption(context, accountOptions[index]);
},
);
},
),
);
}
}

View File

@ -1,89 +0,0 @@
import 'package:flutter/material.dart';
import 'package:mobile_number/mobile_number.dart';
class SimParametersPage extends StatefulWidget {
const SimParametersPage({Key? key}) : super(key: key);
@override
_SimParametersPageState createState() => _SimParametersPageState();
}
class _SimParametersPageState extends State<SimParametersPage> {
List<SimCard> _simCards = [];
@override
void initState() {
super.initState();
_fetchSimParameters();
}
Future<void> _fetchSimParameters() async {
try {
bool permissionsGranted = await MobileNumber.hasPhonePermission;
if (!permissionsGranted) {
await MobileNumber.requestPhonePermission;
// Check again if permission is granted
permissionsGranted = await MobileNumber.hasPhonePermission;
}
if (permissionsGranted) {
List<SimCard>? simCards = await MobileNumber.getSimCards;
if (simCards != null && mounted) {
setState(() {
_simCards = simCards;
});
} else {
print('No SIM cards found');
}
} else {
print('Phone permission denied');
}
} catch (e) {
print('Failed to get SIM cards: $e');
}
}
Widget _buildSimInfo(SimCard sim, int index) {
return Card(
color: Colors.grey[850],
child: ListTile(
title: Text(
'SIM ${index + 1}',
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
'''
Carrier Name: ${sim.carrierName ?? 'N/A'}
Country Iso: ${sim.countryIso ?? 'N/A'}
Display Name: ${sim.displayName ?? 'N/A'}
Slot Index: ${sim.slotIndex ?? 'N/A'}
Number: ${sim.number ?? 'N/A'}
''',
style: const TextStyle(color: Colors.grey),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('SIM Parameters'),
),
body: _simCards.isEmpty
? const Center(
child: Text(
'No SIM cards found',
style: TextStyle(color: Colors.white),
),
)
: ListView.builder(
itemCount: _simCards.length,
itemBuilder: (context, index) {
return _buildSimInfo(_simCards[index], index);
},
),
);
}
}

View File

@ -6,12 +6,11 @@ import 'package:dialer/services/cryptography/asymmetric_crypto_service.dart';
import 'package:provider/provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
const stealthFlag = String.fromEnvironment('STEALTH', defaultValue: 'false');
globals.isStealthMode = stealthFlag.toLowerCase() == 'true';
// Initialize CryptographyService
final AsymmetricCryptoService cryptoService = AsymmetricCryptoService();
// Initialize default key pair
await cryptoService.initializeDefaultKeyPair();
runApp(

View File

@ -52,7 +52,7 @@ class AsymmetricCryptoService {
});
return signature;
} on PlatformException catch (e) {
throw Exception("Failed to sign data: ${e.message}");
throw Exception("Failed to sign data with alias '$alias': ${e.message}");
}
}
@ -72,14 +72,11 @@ class AsymmetricCryptoService {
Future<void> deleteKeyPair(String alias) async {
try {
await _channel.invokeMethod('deleteKeyPair', {'alias': alias});
// Retrieve existing keys
final String? existingKeys = await _secureStorage.read(key: 'keys');
if (existingKeys != null) {
List<dynamic> keysList = jsonDecode(existingKeys);
keysList.removeWhere((key) => key['alias'] == alias);
// Save updated keys list
await _secureStorage.write(key: 'keys', value: jsonEncode(keysList));
}
} on PlatformException catch (e) {
@ -91,11 +88,12 @@ class AsymmetricCryptoService {
Future<List<Map<String, dynamic>>> getAllKeys() async {
try {
final String? existingKeys = await _secureStorage.read(key: 'keys');
if (existingKeys != null) {
List<dynamic> keysList = jsonDecode(existingKeys);
return keysList.cast<Map<String, dynamic>>();
if (existingKeys == null) {
print("No keys found");
return [];
}
return [];
List<dynamic> keysList = jsonDecode(existingKeys);
return keysList.cast<Map<String, dynamic>>();
} catch (e) {
throw Exception("Failed to retrieve keys: $e");
}
@ -115,27 +113,21 @@ class AsymmetricCryptoService {
Future<void> initializeDefaultKeyPair() async {
const String defaultAlias = 'icing_default';
final List<Map<String, dynamic>> keys = await getAllKeys();
// Check if default key exists in metadata
// Check if the key exists in metadata
final bool defaultKeyExists = keys.any((key) => key['alias'] == defaultAlias);
if (!defaultKeyExists) {
// Check if default key exists in Keystore
final bool exists = await keyPairExists(defaultAlias);
if (!exists) {
// Generate default key
await _channel.invokeMethod('generateKeyPair', {'alias': defaultAlias});
// Store metadata
final Map<String, dynamic> keyMetadata = {
'alias': defaultAlias,
'label': 'Default Key',
'created_at': DateTime.now().toIso8601String(),
};
keys.add(keyMetadata);
await _secureStorage.write(key: 'keys', value: jsonEncode(keys));
}
await _channel.invokeMethod('generateKeyPair', {'alias': defaultAlias});
final Map<String, dynamic> keyMetadata = {
'alias': defaultAlias,
'label': 'Default Key',
'created_at': DateTime.now().toIso8601String(),
};
keys.add(keyMetadata);
await _secureStorage.write(key: 'keys', value: jsonEncode(keys));
}
}

View File

@ -1,59 +0,0 @@
## 2.1.1
* Fix Android building
## 2.1.0
* Make min sdk to Flutter 3.0.0
## 2.0.0
* Remove null check operator from method ListenPhone
## 1.0.4
* Null safety support
## 1.0.3
* Fix crash because of null value on empty number
## 1.0.2
* Support old Flutter plugin V1
## 1.0.1
* Fix crash related to Android 10
## 1.0.0
* Addded has phone permission
* Added request phone permission
* Added phone permission listener
* Fix bugs
## 0.0.6
* Add sample image.
## 0.0.5
* Add support for dual sim card.
## 0.0.4
* Print exception message on debugging console.
## 0.0.3
* Migrate to AndroidX
## 0.0.2
* Add gt mobile number native code to Android
## 0.0.1
* Initial Release.

View File

@ -1,13 +0,0 @@
Copyright 2023 Amr Eniou
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,66 +0,0 @@
# mobile_number
This is a FLutter Plugin to get the device mobile number.
#### Note: It works for Android only because getting mobile number of sim card is not supported in iOS.
#### Note: If the mobile number is not pre-exist on sim card it will not return te phone number.
## Installation
#### Link on Flutter plugins
https://pub.dev/packages/mobile_number
#### Note:
if you still using depecated FlutterActivty on MainActivity.java
which is import of
- `import io.flutter.app.FlutterActivity;`
not
- `import io.flutter.embedding.android.FlutterActivity;`
then you need to add the following to your MainActivity.java
```
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MobileNumberPlugin.registerWith(registrarFor("com.amorenew.mobile_number.MobileNumberPlugin()"));
}
```
## Usage
#### Check Phone Permission
```await MobileNumber.hasPhonePermission```
#### Request Phone Permission
```await MobileNumber.requestPhonePermission```
#### Listen to widget resume after Phone Permission request
```MobileNumber.listenPhonePermission((isPermissionGranted) {
if (isPermissionGranted) {
//Get mobile number
} else {
//Request Phone Permission
}
});
```
#### Get first sim card number
```Future<String> getMobileNumber() async {
final String mobileNumber = await MobileNumber.mobileNumber;
return mobileNumber;
}
```
#### Get List of sim cards for dual sim cards
```Future<List<SimCard>> geSimCards() async {
final List<SimCard> simCards = await MobileNumber.getSimCards;
return simCards;
}
```
![alt text](https://raw.githubusercontent.com/amorenew/Flutter-Mobile-Number-Plugin/master/sample1.png)

View File

@ -1,41 +0,0 @@
group 'com.amorenew.mobile_number'
version '1.0-SNAPSHOT'
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.2'
}
}
rootProject.allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 33
namespace "com.amorenew.mobile_number"
defaultConfig {
targetSdkVersion 33
minSdkVersion 21
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
}
dependencies {
implementation 'androidx.core:core:1.9.0'
// Other dependencies...
}

View File

@ -1,3 +0,0 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true

View File

@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -1 +0,0 @@
rootProject.name = 'mobile_number'

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.amorenew.mobile_number"> <!-- Package is "com.amorenew.mobile_number" -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</manifest>

View File

@ -1,262 +0,0 @@
package com.amorenew.mobile_number;
import java.util.HashMap;
import java.util.Map;
class CountryToPhonePrefix {
private static Map<String, String> map = new HashMap<>();
static String prefixFor(String iso2CountryCode) {
String result = map.get(iso2CountryCode.toUpperCase());
if (result == null) {
return "";
}
return result;
}
static {
map.put("AC", "247");
map.put("AD", "376");
map.put("AE", "971");
map.put("AF", "93");
map.put("AG", "1268");
map.put("AI", "1264");
map.put("AL", "355");
map.put("AM", "374");
map.put("AN", "599");
map.put("AO", "244");
map.put("AR", "54");
map.put("AS", "1684");
map.put("AT", "43");
map.put("AU", "61");
map.put("AW", "297");
map.put("AX", "35818");
// map.put("AZ", "37497");
map.put("AZ", "994");
map.put("BA", "387");
map.put("BB", "1246");
map.put("BD", "880");
map.put("BE", "32");
map.put("BF", "226");
map.put("BG", "359");
map.put("BH", "973");
map.put("BI", "257");
map.put("BJ", "229");
map.put("BM", "1441");
map.put("BN", "673");
map.put("BO", "591");
map.put("BR", "55");
map.put("BS", "1242");
map.put("BT", "975");
map.put("BW", "267");
map.put("BY", "375");
map.put("BZ", "501");
map.put("CA", "1");
map.put("CC", "61");
map.put("CD", "243");
map.put("CF", "236");
map.put("CG", "242");
map.put("CH", "41");
map.put("CI", "225");
map.put("CK", "682");
map.put("CL", "56");
map.put("CM", "237");
map.put("CN", "86");
map.put("CO", "57");
map.put("CR", "506");
map.put("CS", "381");
map.put("CU", "53");
map.put("CV", "238");
map.put("CX", "61");
// map.put("CY", "90392");
map.put("CY", "357");
map.put("CZ", "420");
map.put("DE", "49");
map.put("DJ", "253");
map.put("DK", "45");
map.put("DM", "1767");
map.put("DO", "1809"); // and 1829?
map.put("DZ", "213");
map.put("EC", "593");
map.put("EE", "372");
map.put("EG", "20");
map.put("EH", "212");
map.put("ER", "291");
map.put("ES", "34");
map.put("ET", "251");
map.put("FI", "358");
map.put("FJ", "679");
map.put("FK", "500");
map.put("FM", "691");
map.put("FO", "298");
map.put("FR", "33");
map.put("GA", "241");
map.put("GB", "44");
map.put("GD", "1473");
map.put("GE", "995");
map.put("GF", "594");
map.put("GG", "44");
map.put("GH", "233");
map.put("GI", "350");
map.put("GL", "299");
map.put("GM", "220");
map.put("GN", "224");
map.put("GP", "590");
map.put("GQ", "240");
map.put("GR", "30");
map.put("GT", "502");
map.put("GU", "1671");
map.put("GW", "245");
map.put("GY", "592");
map.put("HK", "852");
map.put("HN", "504");
map.put("HR", "385");
map.put("HT", "509");
map.put("HU", "36");
map.put("ID", "62");
map.put("IE", "353");
map.put("IL", "972");
map.put("IM", "44");
map.put("IN", "91");
map.put("IO", "246");
map.put("IQ", "964");
map.put("IR", "98");
map.put("IS", "354");
map.put("IT", "39");
map.put("JE", "44");
map.put("JM", "1876");
map.put("JO", "962");
map.put("JP", "81");
map.put("KE", "254");
map.put("KG", "996");
map.put("KH", "855");
map.put("KI", "686");
map.put("KM", "269");
map.put("KN", "1869");
map.put("KP", "850");
map.put("KR", "82");
map.put("KW", "965");
map.put("KY", "1345");
map.put("KZ", "7");
map.put("LA", "856");
map.put("LB", "961");
map.put("LC", "1758");
map.put("LI", "423");
map.put("LK", "94");
map.put("LR", "231");
map.put("LS", "266");
map.put("LT", "370");
map.put("LU", "352");
map.put("LV", "371");
map.put("LY", "218");
map.put("MA", "212");
map.put("MC", "377");
// map.put("MD", "373533");
map.put("MD", "373");
map.put("ME", "382");
map.put("MG", "261");
map.put("MH", "692");
map.put("MK", "389");
map.put("ML", "223");
map.put("MM", "95");
map.put("MN", "976");
map.put("MO", "853");
map.put("MP", "1670");
map.put("MQ", "596");
map.put("MR", "222");
map.put("MS", "1664");
map.put("MT", "356");
map.put("MU", "230");
map.put("MV", "960");
map.put("MW", "265");
map.put("MX", "52");
map.put("MY", "60");
map.put("MZ", "258");
map.put("NA", "264");
map.put("NC", "687");
map.put("NE", "227");
map.put("NF", "672");
map.put("NG", "234");
map.put("NI", "505");
map.put("NL", "31");
map.put("NO", "47");
map.put("NP", "977");
map.put("NR", "674");
map.put("NU", "683");
map.put("NZ", "64");
map.put("OM", "968");
map.put("PA", "507");
map.put("PE", "51");
map.put("PF", "689");
map.put("PG", "675");
map.put("PH", "63");
map.put("PK", "92");
map.put("PL", "48");
map.put("PM", "508");
map.put("PR", "1787"); // and 1939 ?
map.put("PS", "970");
map.put("PT", "351");
map.put("PW", "680");
map.put("PY", "595");
map.put("QA", "974");
map.put("RE", "262");
map.put("RO", "40");
map.put("RS", "381");
map.put("RU", "7");
map.put("RW", "250");
map.put("SA", "966");
map.put("SB", "677");
map.put("SC", "248");
map.put("SD", "249");
map.put("SE", "46");
map.put("SG", "65");
map.put("SH", "290");
map.put("SI", "386");
map.put("SJ", "47");
map.put("SK", "421");
map.put("SL", "232");
map.put("SM", "378");
map.put("SN", "221");
map.put("SO", "252");
map.put("SR", "597");
map.put("ST", "239");
map.put("SV", "503");
map.put("SY", "963");
map.put("SZ", "268");
map.put("TA", "290");
map.put("TC", "1649");
map.put("TD", "235");
map.put("TG", "228");
map.put("TH", "66");
map.put("TJ", "992");
map.put("TK", "690");
map.put("TL", "670");
map.put("TM", "993");
map.put("TN", "216");
map.put("TO", "676");
map.put("TR", "90");
map.put("TT", "1868");
map.put("TV", "688");
map.put("TW", "886");
map.put("TZ", "255");
map.put("UA", "380");
map.put("UG", "256");
map.put("US", "1");
map.put("UY", "598");
map.put("UZ", "998");
map.put("VA", "379");
map.put("VC", "1784");
map.put("VE", "58");
map.put("VG", "1284");
map.put("VI", "1340");
map.put("VN", "84");
map.put("VU", "678");
map.put("WF", "681");
map.put("WS", "685");
map.put("YE", "967");
map.put("YT", "262");
map.put("ZA", "27");
map.put("ZM", "260");
map.put("ZW", "263");
}}

View File

@ -1,248 +0,0 @@
package com.amorenew.mobile_number;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import org.json.JSONArray;
import java.util.ArrayList;
import java.util.List;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener;
/**
* MobileNumberPlugin
*/
public class MobileNumberPlugin implements FlutterPlugin, ActivityAware, MethodCallHandler, RequestPermissionsResultListener {
private static final int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 0;
final String Event_phonePermissionResult = "requestPhonePermission=";
private EventChannel.EventSink permissionEvent;
private Context applicationContext;
private Activity activity;
private TelephonyManager telephonyManager;
private Result result;
private MethodChannel methodChannel;
private EventChannel permissionEventChannel;
/**
* Plugin registration.
*/
public static void registerWith(Registrar registrar) {
final MobileNumberPlugin instance = new MobileNumberPlugin();
instance.onAttachedToEngine(registrar.context(), registrar.messenger(), registrar.activity());
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
onAttachedToEngine(flutterPluginBinding.getApplicationContext(), flutterPluginBinding.getBinaryMessenger(), null);
}
private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger, Activity _activity) {
this.applicationContext = applicationContext;
if(_activity!=null)
this.activity=_activity;
methodChannel = new MethodChannel(messenger, "mobile_number");
methodChannel.setMethodCallHandler(this);
permissionEventChannel = new EventChannel(messenger, "phone_permission_event");
permissionEventChannel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
permissionEvent = eventSink;
}
@Override
public void onCancel(Object o) {
}
});
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
}
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) {
//MobileNumberPlugin.activity = activityPluginBinding.getActivity();
//activityV2 = activityPluginBinding.getActivity();
activity = activityPluginBinding.getActivity();
}
@Override
public void onDetachedFromActivityForConfigChanges() {
}
@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding activityPluginBinding) {
}
@Override
public void onDetachedFromActivity() {
}
@Override
public void onMethodCall(MethodCall call, Result result) {
this.result = result;
final String method_GetMobileNumber = "getMobileNumber";
final String method_hasPhonePermission = "hasPhonePermission";
final String method_requestPhonePermission = "requestPhonePermission";
switch (call.method) {
case method_GetMobileNumber:
telephonyManager = (TelephonyManager) applicationContext
.getSystemService(Context.TELEPHONY_SERVICE);
getMobileNumber();
break;
case method_hasPhonePermission:
result.success(hasPhonePermission());
break;
case method_requestPhonePermission:
requestPhonePermission();
break;
default:
result.notImplemented();
break;
}
}
private boolean hasPhonePermission() {
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
return ContextCompat.checkSelfPermission(applicationContext,
Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED;
} else {
return ContextCompat.checkSelfPermission(applicationContext,
Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED;
}
}
private void requestPhonePermission() {
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
Manifest.permission.READ_PHONE_NUMBERS)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.READ_PHONE_NUMBERS}, MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
}
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
Manifest.permission.READ_PHONE_STATE)) {
} else {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.READ_PHONE_STATE}, MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
}
}
}
private void getMobileNumber() {
if (!hasPhonePermission()) {
requestPhonePermission();
} else {
// Permission has already been granted
generateMobileNumber();
}
}
@SuppressLint("HardwareIds")
private void generateMobileNumber() {
JSONArray simJsonArray = new JSONArray();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
for (SubscriptionInfo subscriptionInfo : getSubscriptions()) {
SimCard simCard = new SimCard(telephonyManager, subscriptionInfo);
simJsonArray.put(simCard.toJSON());
}
}
if (simJsonArray.length()==0) {
SimCard simCard = getSingleSimCard();
if (simCard != null) {
simJsonArray.put(simCard.toJSON());
}
}
if (simJsonArray.toString().isEmpty()) {
Log.d("UNAVAILABLE", "No phone number on sim card#3");
result.error("UNAVAILABLE", "No phone number on sim card", null);
} else result.success(simJsonArray.toString());
}
@SuppressLint("HardwareIds")
SimCard getSingleSimCard() {
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_DENIED
&& ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED) {
Log.e("UNAVAILABLE", "No phone number on sim card Permission Denied#2", null);
return null;
} else if (telephonyManager.getLine1Number() == null || telephonyManager.getLine1Number().isEmpty()) {
Log.e("UNAVAILABLE", "No phone number on sim card#2", null);
return null;
}
return new SimCard(telephonyManager);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
List<SubscriptionInfo> getSubscriptions() {
final SubscriptionManager subscriptionManager = (SubscriptionManager) activity.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_DENIED
&& ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED) {
Log.e("UNAVAILABLE", "No phone number on sim card Permission Denied#1", null);
return new ArrayList<>();
} else if (subscriptionManager == null) {
Log.e("UNAVAILABLE", "No phone number on sim card#1", null);
return new ArrayList<>();
}
return subscriptionManager.getActiveSubscriptionInfoList();
}
@Override
public boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
// If request is cancelled, the result arrays are empty.
if (requestCode == MY_PERMISSIONS_REQUEST_READ_PHONE_STATE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (permissionEvent != null)
permissionEvent.success(true);
generateMobileNumber();
return true;
} else {
if (permissionEvent != null)
permissionEvent.success(false);
}
}
result.error("PERMISSION", "onRequestPermissionsResult is not granted", null);
return false;
}
}

View File

@ -1,73 +0,0 @@
package com.amorenew.mobile_number;
import android.annotation.SuppressLint;
import android.os.Build;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import androidx.annotation.RequiresApi;
import org.json.JSONException;
import org.json.JSONObject;
public class SimCard {
private String carrierName = "";
private String displayName = "";
private int slotIndex = 0;
private String number = "";
private String countryIso = "";
private String countryPhonePrefix = "";
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
public SimCard(TelephonyManager telephonyManager, SubscriptionInfo subscriptionInfo) {
this.carrierName = subscriptionInfo.getCarrierName().toString();
this.displayName = subscriptionInfo.getDisplayName().toString();
this.slotIndex = subscriptionInfo.getSimSlotIndex();
this.number = subscriptionInfo.getNumber();
if (subscriptionInfo.getCountryIso() != null && !subscriptionInfo.getCountryIso().isEmpty())
this.countryIso = subscriptionInfo.getCountryIso();
else if (telephonyManager.getSimCountryIso() != null)
this.countryIso = telephonyManager.getSimCountryIso();
this.countryPhonePrefix = CountryToPhonePrefix.prefixFor(this.countryIso);
}
@SuppressLint({"MissingPermission", "HardwareIds"})
public SimCard(TelephonyManager telephonyManager) {
if (telephonyManager.getSimOperator() != null)
carrierName = telephonyManager.getSimOperatorName();
if (telephonyManager.getSimOperator() != null)
displayName = telephonyManager.getSimOperatorName();
if (telephonyManager.getSimCountryIso() != null) {
countryIso = telephonyManager.getSimCountryIso();
countryPhonePrefix = CountryToPhonePrefix.prefixFor(countryIso);
}
if (telephonyManager.getLine1Number() != null && !telephonyManager.getLine1Number().isEmpty()) {
if (telephonyManager.getLine1Number().startsWith("0"))
number = countryPhonePrefix + telephonyManager.getLine1Number().substring(1);
number = telephonyManager.getLine1Number();
}
}
// final JSONArray jsonArray = new JSONArray();
JSONObject toJSON() {
JSONObject json = new JSONObject();
try {
json.put("carrierName", carrierName);
json.put("displayName", displayName);
json.put("slotIndex", slotIndex);
json.put("number", number);
json.put("countryIso", countryIso);
json.put("countryPhonePrefix", countryPhonePrefix);
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
}

View File

@ -1,16 +0,0 @@
# mobile_number_example
Demonstrates how to use the mobile_number plugin.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View File

@ -1,58 +0,0 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
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.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdk 33
defaultConfig {
applicationId "com.icingDialer.mobile_number_example"
minSdkVersion 21
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
signingConfig signingConfigs.debug
}
}
lint {
disable 'InvalidPackage'
}
}
flutter {
source '../..'
}
dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

View File

@ -1,7 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mobile_number_example">
<!-- Flutter 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>

View File

@ -1,58 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mobile_number_example">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:label="mobile_number_example">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
</activity>
<activity
android:name=".EmbeddingV1Activity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale"
android:hardwareAccelerated="true"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize" />
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

View File

@ -1,14 +0,0 @@
package com.example.mobile_number_example;
import android.os.Bundle;
import com.amorenew.mobile_number.MobileNumberPlugin;
import io.flutter.app.FlutterActivity;
public class EmbeddingV1Activity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MobileNumberPlugin.registerWith(registrarFor("com.amorenew.mobile_number.MobileNumberPlugin()"));
}
}

View File

@ -1,15 +0,0 @@
package com.example.mobile_number_example;
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends FlutterActivity {
// @Override
// public void configureFlutterEngine(FlutterEngine flutterEngine) {
// super.configureFlutterEngine(flutterEngine);
// flutterEngine.getPlugins().add(new com.example.mobile_number.MobileNumberPlugin());
// }
}

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">@android:color/white</item>
</style>
</resources>

View File

@ -1,7 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mobile_number_example">
<!-- Flutter 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>

View File

@ -1,29 +0,0 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.2'
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -1,4 +0,0 @@
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true

View File

@ -1,6 +0,0 @@
#Tue May 19 14:57:48 GST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip

View File

@ -1,15 +0,0 @@
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>

View File

@ -1,2 +0,0 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View File

@ -1,2 +0,0 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

View File

@ -1,84 +0,0 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
generated_key_values = {}
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
end
generated_key_values
end
target 'Runner' do
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter')
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
# Plugin Pods
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end

View File

@ -1,506 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
97C146F21CF9000F007C117D /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = S8QB4VV633;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.mobileNumberExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.mobileNumberExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.mobileNumberExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,6 +0,0 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end

View File

@ -1,13 +0,0 @@
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

View File

@ -1,122 +0,0 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,23 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

View File

@ -1,5 +0,0 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Icing Dialer</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@ -1,9 +0,0 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View File

@ -1,78 +0,0 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mobile_number/mobile_number.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _mobileNumber = '';
List<SimCard> _simCard = <SimCard>[];
@override
void initState() {
super.initState();
MobileNumber.listenPhonePermission((isPermissionGranted) {
if (isPermissionGranted) {
initMobileNumberState();
} else {}
});
initMobileNumberState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initMobileNumberState() async {
if (!await MobileNumber.hasPhonePermission) {
await MobileNumber.requestPhonePermission;
return;
}
// Platform messages may fail, so we use a try/catch PlatformException.
try {
_mobileNumber = (await MobileNumber.mobileNumber)!;
_simCard = (await MobileNumber.getSimCards)!;
} on PlatformException catch (e) {
debugPrint("Failed to get mobile number because of '${e.message}'");
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {});
}
Widget fillCards() {
List<Widget> widgets = _simCard
.map((SimCard sim) => Text(
'Sim Card Number: (${sim.countryPhonePrefix}) - ${sim.number}\nCarrier Name: ${sim.carrierName}\nCountry Iso: ${sim.countryIso}\nDisplay Name: ${sim.displayName}\nSim Slot Index: ${sim.slotIndex}\n\n'))
.toList();
return Column(children: widgets);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: <Widget>[
Text('Running on: $_mobileNumber\n'),
fillCards()
],
),
),
),
);
}
}

View File

@ -1,64 +0,0 @@
name: mobile_number_example
description: Demonstrates how to use the mobile_number plugin.
publish_to: 'none'
environment:
sdk: ">=2.12.0 <3.0.0"
flutter: ">=2.0.0"
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
mobile_number:
path: ../
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages

View File

@ -1,27 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
// import 'package:flutter/material.dart';
// import 'package:flutter_test/flutter_test.dart';
// import '../../example/lib/main.dart';
void main() {
// testWidgets('Verify Platform version', (WidgetTester tester) async {
// // Build our app and trigger a frame.
// await tester.pumpWidget(MyApp());
// // Verify that platform version is retrieved.
// expect(
// find.byWidgetPredicate(
// (Widget widget) => widget is Text &&
// widget.data.startsWith('Running on:'),
// ),
// findsOneWidget,
// );
// });
}

View File

@ -1,4 +0,0 @@
#import <Flutter/Flutter.h>
@interface MobileNumberPlugin : NSObject<FlutterPlugin>
@end

View File

@ -1,20 +0,0 @@
#import "MobileNumberPlugin.h"
@implementation MobileNumberPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"mobile_number"
binaryMessenger:[registrar messenger]];
MobileNumberPlugin* instance = [[MobileNumberPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
} else {
result(FlutterMethodNotImplemented);
}
}
@end

View File

@ -1,21 +0,0 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = 'mobile_number'
s.version = '0.0.1'
s.summary = 'A new flutter plugin project.'
s.description = <<-DESC
A new flutter plugin project.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.ios.deployment_target = '8.0'
end

View File

@ -1,65 +0,0 @@
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:mobile_number/sim_card.dart';
import 'package:mobile_number/widget_lifecycle.dart';
export 'package:mobile_number/sim_card.dart';
export 'package:mobile_number/widget_lifecycle.dart';
class MobileNumber {
static const MethodChannel _channel = const MethodChannel('mobile_number');
static void listenPhonePermission(
Function(bool isPermissionGranted) subscription,
) {
WidgetsBinding.instance.addObserver(
WidgetLifecycle(
resumeCallBack: (() async {
if (await MobileNumber.hasPhonePermission) {
subscription(true);
} else {
subscription(false);
}
}),
),
);
}
static Future<bool> get hasPhonePermission async {
final bool hasPermission =
await _channel.invokeMethod('hasPhonePermission');
return hasPermission;
}
static Future<void> get requestPhonePermission async {
await _channel.invokeMethod('requestPhonePermission');
}
static Future<String>? get mobileNumber async {
final String simCardsJson = await _channel.invokeMethod('getMobileNumber');
if (simCardsJson.isEmpty) {
return '';
}
List<SimCard> simCards = SimCard.parseSimCards(simCardsJson);
if (simCards.isNotEmpty && simCards[0].number != null) {
return simCards[0].countryPhonePrefix! + simCards[0].number!;
} else {
return '';
}
}
static Future<List<SimCard>>? get getSimCards async {
final String simCardsJson = await _channel.invokeMethod('getMobileNumber');
if (simCardsJson.isEmpty) {
return <SimCard>[];
}
List<SimCard> simCards = SimCard.parseSimCards(simCardsJson);
if (simCards.isNotEmpty) {
return simCards;
} else {
return <SimCard>[];
}
}
}

View File

@ -1,43 +0,0 @@
import 'dart:convert';
class SimCard {
final String? carrierName;
final String? displayName;
final int? slotIndex;
final String? number;
final String? countryIso;
final String? countryPhonePrefix;
SimCard({
this.carrierName,
this.displayName,
this.slotIndex,
this.number,
this.countryIso,
this.countryPhonePrefix,
});
factory SimCard.fromMap(Map<String, dynamic> json) => SimCard(
carrierName: json["carrierName"],
displayName: json["displayName"],
slotIndex: json["slotIndex"],
number: json["number"],
countryIso: json["countryIso"],
countryPhonePrefix: json["countryPhonePrefix"],
);
Map<String, dynamic> toMap() => {
"carrierName": carrierName,
"displayName": displayName,
"slotIndex": slotIndex,
"number": number,
"countryIso": countryIso,
"countryPhonePrefix": countryPhonePrefix,
};
static List<SimCard> parseSimCards(String str) =>
List<SimCard>.from(json.decode(str).map((x) => SimCard.fromMap(x)));
static String simCardToJson(List<SimCard> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toMap())));
}

View File

@ -1,30 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
class WidgetLifecycle extends WidgetsBindingObserver {
final AsyncCallback? resumeCallBack;
final AsyncCallback? suspendingCallBack;
WidgetLifecycle({
this.resumeCallBack,
this.suspendingCallBack,
});
@override
Future<Null> didChangeAppLifecycleState(AppLifecycleState state) async {
switch (state) {
case AppLifecycleState.resumed:
if (resumeCallBack != null) {
await resumeCallBack!();
}
break;
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
if (suspendingCallBack != null) {
await suspendingCallBack!();
}
break;
}
}
}

View File

@ -1,9 +0,0 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Jun 03 03:03:49 EET 2019
ndk.dir=D\:\\Programming\\Android\\Tools\\Android_SDK\\ndk-bundle
sdk.dir=D\:\\Programming\\Android\\Tools\\Android_SDK

Some files were not shown because too many files have changed in this diff Show More