
就在前不久,西建大iOS Club 社团 AI 安卓版App正式上线了。其实也是正好,正好我在学Flutter,就想着拿Flutter搞个社团AI App出来。
然后,就搞出来了。
好多人不会搞PWA,怎么办
PWA,简单来讲就是你可以直接把网站 "安装" 到设备上。这样你就可以快速访问了。像社团有些网站就支持PWA(建大百科、iOS 图书馆、社团AI)。
而非常好的一点就在于,社团AI使用的开源前端项目LobeChat就支持PWA。如果你想 "安装" 社团AI,你只需要在Edge上打开社团AI网站,他自己就会跳出安装的弹窗。
但问题是很多人用的并不是Edge(我也不知道谷歌浏览器和火狐支不支持PWA),而是手机自带的浏览器。这种浏览器是不支持PWA的。
那么就很没办法,不能快速访问到社团AI,这也就导致很多人使用社团AI都是在电脑上用的。
其实在今年1月之前,我就想过要不要搞一个移动端的社团AI,但是我电脑上的Flutter环境死活也配置不好(其实就是因为我用户名是中文),而且自己写一个有点太麻烦了,所以就一直搁置了下来。
直到,有人说了这样一句话:
直接拿WebView包装一下,搞个App出来
把网站 "包装" 进去
他讲到的,其实就是在App上直接访问网站。相当于就是放了个 "浏览器" 上去。
而与此同时,我也把Windows用户名问题给解决了。正好我也不用从头开始写个App出来。所以,直接开搞了。
其实整个的代码逻辑很简单,放个WebView进去就行了。这里我使用的WebView库是 flutter_inappwebview。
flutter pub add flutter_inappwebview
然后就直接在 lib/main.dart 上开写就行:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: theme.scaffoldBackgroundColor, // 状态栏背景颜色
statusBarIconBrightness: theme.brightness == Brightness.dark
? Brightness.light // 如果是深色主题,图标为亮色
: Brightness.dark, // 如果是浅色主题,图标为暗色
));
return MaterialApp(
title: 'iOS AI',
theme: ThemeData(primarySwatch: Colors.blue),
home: const WebViewScreen(),
);
}
}
class WebViewScreen extends StatefulWidget {
const WebViewScreen({super.key});
@override
State<WebViewScreen> createState() => _WebViewScreenState();
}
class _WebViewScreenState extends State<WebViewScreen> {
late final InAppWebViewController _controller;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: true,
child: InAppWebView(
initialUrlRequest: URLRequest(
url:
WebUri.uri(Uri.parse('https://gpt.xauat.site/')), // 替换为你的网站URL
),
),
),
);
}
}
就直接在SafeArea里套个InAppWebView就行了。
但是如果你现在运行,你就会发现:
欸,怎么显示不出来?
设置权限
这里其实是因为,你没有设置相关的权限。
现在我们来到这个文件:
android/app/src/main/AndroidManifest.xml
直接在下面加个权限:
<uses-permission
android:name="android.permission.INTERNET"
tools:ignore="ManifestOrder" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
现在再运行,OK了。
要是还不行,直接实机测试
写一个返回事件
我们测试的时候会发现一点:我们无法使用返回手势进行页面返回操作,直接退出App了。
这里因为WebView的回退跟应用的返回事件并没有任何关联。怎么办?我们给他加上这层关联不就行了?
所以我们这里得使用WillPopScope控件了。而且我们得把WebView的控件给保留下来。我们的代码得这么写:
class _WebViewScreenState extends State<WebViewScreen> {
late final InAppWebViewController _controller;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
final canGoBack = await _controller.canGoBack();
if (canGoBack) {
_controller.goBack();
}
// 允许关闭页面
return !canGoBack;
},
child: Scaffold(
body: SafeArea(
top: true,
child: InAppWebView(
initialUrlRequest: URLRequest(
url:
WebUri.uri(Uri.parse('https://gpt.xauat.site/')), // 替换为你的网站URL
),
initialSettings: InAppWebViewSettings(
javaScriptEnabled: true,
mediaPlaybackRequiresUserGesture: false,
databaseEnabled: true,
// Android 专属
useHybridComposition: true,
allowFileAccess: true,
allowContentAccess: true,
domStorageEnabled: true,
// 启用本地存储
allowsInlineMediaPlayback: true,
allowsBackForwardNavigationGestures: true,
),
onWebViewCreated: (controller) {
_controller = controller;
},
onPermissionRequest: (controller, request) async {
return PermissionResponse(
resources: request.resources,
action: PermissionResponseAction.GRANT,
);
},
),
),
),
);
}
}
当我们进行返回操作时,WillPopScope控件会触发onWillPop事件。而onWillPop事件中,我们规定,当WebView不能进行历史回退时,就直接退出,如果可以,进行历史回退而不退出应用。
同时我们也开启一下WebView的权限,这样就能正常运行网站了。
现在,我们就可以使用返回手势进行历史回退操作了。
想访问手机图片或者文件夹,怎么办
目前最新的LobeChat支持图片解析,同时服务端数据库版的LaobeChat支持文件解析和知识库。但是当我们上传图片时,会无法调用。这是为什么呢?
因为没有权限嘛。
所以我们得去趟刚才设置权限的地方:
android/app/src/main/AndroidManifest.xml
设置一下:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />
当然我们还可以让用户帮我们设置权限。我们先安装这个库:
flutter pub add permission_handler
然后在初始化的时候让用户自己选择要不要打开该权限:
import 'package:permission_handler/permission_handler.dart';
...
class _WebViewScreenState extends State<WebViewScreen> {
late final InAppWebViewController _controller;
@override
void initState() {
super.initState();
// 初始化逻辑转移到 WebView 属性中
requestPermissions();
}
Future<void> requestPermissions() async {
await [
Permission.camera,
Permission.microphone,
Permission.storage,
Permission.speech
].request();
}
...(中间代码省略)
}
这样就可以了!
发布
现在,我们就可以发布了!
但是在发布之前还得设置一下你的App图标:

然后在控制台输入这个即可:
flutter build apk
这样就可以了!
当然,因为我没有苹果电脑,所以我生成不了iOS平台的安装包。所以这期并不涉及iOS平台。
End
到这里就结束了,具体的项目地址在这里