Android CA Install guide

This commit is contained in:
wanghongenpin
2024-03-25 16:26:21 +08:00
parent 70427635cc
commit 0e4447cdbc
6 changed files with 136 additions and 64 deletions

View File

@@ -237,6 +237,8 @@ class _SslState extends State<SslWidget> {
]),
ListView(
children: [
Text(localizations.androidUserCATips, style: const TextStyle(fontWeight: FontWeight.w500)),
const SizedBox(height: 10),
SelectableText.rich(TextSpan(
text:
"1. ${localizations.configWifiProxy} Host$host Port${widget.proxyServer.port}")),

View File

@@ -83,7 +83,6 @@ class _AppWhitelistState extends State<AppWhitelist> {
body: FutureBuilder(
future: Future.wait(appWhitelist),
builder: (BuildContext context, AsyncSnapshot<List<AppInfo>> snapshot) {
print(snapshot.data);
if (snapshot.hasData) {
if (snapshot.data!.isEmpty) {
return Center(

View File

@@ -1,9 +1,13 @@
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_toastr/flutter_toastr.dart';
import 'package:network_proxy/network/bin/server.dart';
import 'package:network_proxy/network/util/crts.dart';
import 'package:network_proxy/network/util/file_read.dart';
import 'package:network_proxy/utils/lang.dart';
import 'package:url_launcher/url_launcher.dart';
class MobileSslWidget extends StatefulWidget {
@@ -36,7 +40,7 @@ class _MobileSslState extends State<MobileSslWidget> {
title: Text(localizations.httpsProxy, style: const TextStyle(fontSize: 16)),
centerTitle: true,
),
body: ListView(children: [
body: Column(children: [
SwitchListTile(
hoverColor: Colors.transparent,
title: Text(localizations.enabledHttps),
@@ -48,13 +52,13 @@ class _MobileSslState extends State<MobileSslWidget> {
CertificateManager.cleanCache();
setState(() {});
}),
Platform.isIOS ? ios() : Padding(padding: const EdgeInsets.only(left: 15), child: android()),
const SizedBox(height: 20)
Expanded(child: Platform.isIOS ? ios() : const AndroidCaInstall()),
// const SizedBox(height: 20)
]));
}
Widget ios() {
return Column(children: [
return ListView(children: [
// if (localizations.localeName != 'zh')
// ExpansionTile(
// title: Text(localizations.useGuide),
@@ -89,64 +93,127 @@ class _MobileSslState extends State<MobileSslWidget> {
]);
}
Widget android() {
bool isCN = localizations.localeName == 'zh';
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(localizations.installRootCa),
ExpansionTile(
title: Text(localizations.androidRoot, style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 14)),
tilePadding: const EdgeInsets.only(left: 0),
expandedAlignment: Alignment.topLeft,
initiallyExpanded: true,
shape: const Border(),
children: [
Text(localizations.androidRootMagisk),
TextButton(
child: Text("https://${isCN ? 'gitee' : 'github'}.com/wanghongenpin/Magisk-ProxyPinCA/releases"),
onPressed: () {
launchUrl(
Uri.parse("https://${isCN ? 'gitee' : 'github'}.com/wanghongenpin/Magisk-ProxyPinCA/releases"));
}),
SelectableText(localizations.androidRootRename),
]),
const SizedBox(height: 20),
ExpansionTile(
title: Text(localizations.androidUserCA, style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 14)),
tilePadding: const EdgeInsets.only(left: 0),
expandedAlignment: Alignment.topLeft,
expandedCrossAxisAlignment: CrossAxisAlignment.start,
initiallyExpanded: true,
shape: const Border(),
children: [
TextButton(
onPressed: () => _downloadCert(),
child: Text.rich(TextSpan(children: [
TextSpan(text: "1. ${localizations.downloadRootCa} "),
WidgetSpan(child: SelectableText("http://127.0.0.1:${widget.proxyServer.port}/ssl"))
]))),
TextButton(onPressed: () {}, child: Text("2. ${localizations.androidUserCAInstall}")),
TextButton(
onPressed: () {
launchUrl(Uri.parse(isCN
? "https://gitee.com/wanghongenpin/network-proxy-flutter/wikis/%E5%AE%89%E5%8D%93%E6%97%A0ROOT%E4%BD%BF%E7%94%A8Xposed%E6%A8%A1%E5%9D%97%E6%8A%93%E5%8C%85"
: "https://github.com/wanghongenpin/network_proxy_flutter/wiki/Android-without-ROOT-uses-Xposed-module-to-capture-packets"));
},
child: Text(localizations.androidUserXposed)),
ClipRRect(
child: Align(
alignment: Alignment.topCenter,
heightFactor: .7,
child: Image.network(
"https://foruda.gitee.com/images/1689352695624941051/74e3bed6_1073801.png",
height: 680,
)))
])
]);
}
void _downloadCert() async {
CertificateManager.cleanCache();
launchUrl(Uri.parse("http://127.0.0.1:${widget.proxyServer.port}/ssl"), mode: LaunchMode.externalApplication);
}
}
class AndroidCaInstall extends StatefulWidget {
const AndroidCaInstall({super.key});
@override
State<StatefulWidget> createState() => _AndroidCaInstallState();
}
class _AndroidCaInstallState extends State<AndroidCaInstall> with SingleTickerProviderStateMixin {
late TabController _tabController;
AppLocalizations get localizations => AppLocalizations.of(context)!;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
endDrawerEnableOpenDragGesture: false,
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(localizations.installRootCa, style: const TextStyle(fontSize: 16)),
bottom: TabBar(
controller: _tabController,
labelPadding: const EdgeInsets.symmetric(horizontal: 5),
tabs: <Widget>[
Tab(text: localizations.androidRoot),
Tab(text: localizations.androidUserCA),
])),
body: TabBarView(controller: _tabController, children: [rootCA(), userCA()]));
}
rootCA() {
bool isCN = localizations.localeName == 'zh';
return ListView(padding: const EdgeInsets.all(10), children: [
Text(localizations.androidRootMagisk),
TextButton(
child: Text("https://${isCN ? 'gitee' : 'github'}.com/wanghongenpin/Magisk-ProxyPinCA/releases"),
onPressed: () {
launchUrl(Uri.parse("https://${isCN ? 'gitee' : 'github'}.com/wanghongenpin/Magisk-ProxyPinCA/releases"));
}),
const SizedBox(height: 15),
SelectableText(localizations.androidRootRename, style: const TextStyle(fontWeight: FontWeight.w500)),
const SizedBox(height: 10),
FilledButton(onPressed: () => _downloadCert('243f0bfb.0'), child: Text(localizations.androidRootCADownload)),
const SizedBox(height: 10),
Text(
"Android 13: ${isCN ? "将证书挂载到" : "Mount the certificate to"} '/system/etc/security/cacerts' ${isCN ? "目录" : "Directory"}"
.fixAutoLines()),
const SizedBox(height: 5),
Text(
"Android 14: ${isCN ? "将证书挂载到" : "Mount the certificate to"} '/apex/com.android.conscrypt/cacerts' ${isCN ? "目录" : "Directory"}"
.fixAutoLines()),
const SizedBox(height: 5),
ClipRRect(
child: Align(
alignment: Alignment.topCenter,
child: Image.network(
scale: 0.5,
"https://foruda.gitee.com/images/1710181660282752846/cb520c0b_1073801.png",
height: 460,
)))
]);
}
userCA() {
bool isCN = localizations.localeName == 'zh';
return ListView(padding: const EdgeInsets.all(10), children: [
Text(localizations.androidUserCATips, style: const TextStyle(fontWeight: FontWeight.w500)),
const SizedBox(height: 5),
TextButton(
style: const ButtonStyle(alignment: Alignment.centerLeft),
onPressed: () {},
child: Text("1. ${localizations.downloadRootCa} ", textAlign: TextAlign.left),
),
FilledButton(onPressed: () => _downloadCert('243f0bfb.0'), child: Text(localizations.downloadRootCa)),
const SizedBox(height: 5),
TextButton(onPressed: () {}, child: Text("2. ${localizations.androidUserCAInstall}")),
TextButton(
onPressed: () {
launchUrl(Uri.parse(isCN
? "https://gitee.com/wanghongenpin/network-proxy-flutter/wikis/%E5%AE%89%E5%8D%93%E6%97%A0ROOT%E4%BD%BF%E7%94%A8Xposed%E6%A8%A1%E5%9D%97%E6%8A%93%E5%8C%85"
: "https://github.com/wanghongenpin/network_proxy_flutter/wiki/Android-without-ROOT-uses-Xposed-module-to-capture-packets"));
},
child: Text(localizations.androidUserXposed)),
ClipRRect(
child: Align(
alignment: Alignment.topCenter,
heightFactor: .7,
child: Image.network(
"https://foruda.gitee.com/images/1689352695624941051/74e3bed6_1073801.png",
height: 680,
)))
]);
}
void _downloadCert(String name) async {
String? outputFile = await FilePicker.platform.saveFile(
dialogTitle: 'Please select the path to save:',
fileName: name,
bytes: await FileRead.read('assets/certs/ca.crt'));
if (outputFile != null && mounted) {
AppLocalizations localizations = AppLocalizations.of(context)!;
FlutterToastr.show(localizations.success, context);
}
}
}