flutter探险之(1) 十分钟让你体验视频通话APP
开发步骤:1 flutter环境。fultter create你的项目名称cd你的项目名称fultter run确认你能正常的运行起来。这步骤不能算在十分钟内。如果你不熟悉可参考下面的链接再来:https://blog.csdn.net/ldy889/article/details/1030227252、增加依赖。这个真是无语。好像大家都是依赖来依赖去的。...
·
开发步骤:
1 flutter环境。
fultter create 你的项目名称
cd 你的项目名称
fultter run
确认你能正常的运行起来。这步骤不能算在十分钟内。如果你不熟悉可参考下面的链接再来:
https://blog.csdn.net/ldy889/article/details/103022725
2、增加依赖。这个真是无语。好像大家都是依赖来依赖去的。
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
# add agora rtc sdk
agora_rtc_engine: 1.0.1
permission_handler: ^3.0.0
确认保存后有执行:flutter packages get
3.agora_rtc_engine这个插件还需要注册。
// Agora AppId
const APP_ID = "49dxxxxxxa4f258ad";
// https://console.agora.io/projects
// yasg aa11
是的这里就要APP_ID ,没有其他代码了。
附加这个插件条件还是比较苛刻的,但对于flutter开发APP还是购了。如果是微信开发,微信浏览器不支持没办法。
4、 项目列表如下,flutter框架下其实我们的代码都在Lib下。
下面我贴下这4个文件的代码,然后就可以试着跑一下了。
src\pages\call.dart index.dart settings.dart main.dart
main.dart
import 'package:flutter/material.dart';
import './src/pages/index.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: IndexPage(),
);
}
}
setting.dart
// Agora AppId
const APP_ID = "49daxxxxxa54b284a4f258ad";
index.dart
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import './call.dart';
class IndexPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new IndexState();
}
}
class IndexState extends State<IndexPage> {
/// create a channelController to retrieve text value
final _channelController = TextEditingController();
/// if channel textfield is validated to have error
bool _validateError = false;
@override
void dispose() {
// dispose input controller
_channelController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Agora Flutter QuickStart'),
),
body: Center(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
height: 400,
child: Column(
children: <Widget>[
Row(children: <Widget>[]),
Row(children: <Widget>[
Expanded(
child: TextField(
controller: _channelController,
decoration: InputDecoration(
errorText: _validateError
? "Channel name is mandatory"
: null,
border: UnderlineInputBorder(
borderSide: BorderSide(width: 1)),
hintText: 'Channel name'),
))
]),
Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
onPressed: () => onJoin(),
child: Text("Join"),
color: Colors.blueAccent,
textColor: Colors.white,
),
)
],
))
],
)),
));
}
onJoin() async {
// update input validation
setState(() {
_channelController.text.isEmpty
? _validateError = true
: _validateError = false;
});
if (_channelController.text.isNotEmpty) {
// await for camera and mic permissions before pushing video page
await _handleCameraAndMic();
// push video page with given channel name
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => new CallPage(
channelName: _channelController.text,
)));
}
}
_handleCameraAndMic() async {
await PermissionHandler().requestPermissions(
[PermissionGroup.camera, PermissionGroup.microphone]);
}
}
call.dart
import 'dart:async';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/material.dart';
import '../utils/settings.dart';
class CallPage extends StatefulWidget {
/// non-modifiable channel name of the page
final String channelName;
/// Creates a call page with given channel name.
const CallPage({Key key, this.channelName}) : super(key: key);
@override
_CallPageState createState() {
return new _CallPageState();
}
}
class _CallPageState extends State<CallPage> {
static final _users = List<int>();
final _infoStrings = <String>[];
bool muted = false;
@override
void dispose() {
// clear users
_users.clear();
// destroy sdk
AgoraRtcEngine.leaveChannel();
AgoraRtcEngine.destroy();
super.dispose();
}
@override
void initState() {
super.initState();
// initialize agora sdk
initialize();
}
void initialize() {
if (APP_ID.isEmpty) {
setState(() {
_infoStrings
.add("APP_ID missing, please provide your APP_ID in settings.dart");
_infoStrings.add("Agora Engine is not starting");
});
return;
}
_initAgoraRtcEngine();
_addAgoraEventHandlers();
AgoraRtcEngine.enableWebSdkInteroperability(true);
AgoraRtcEngine.setParameters('{\"che.video.lowBitRateStreamParameter\":{\"width\":320,\"height\":180,\"frameRate\":15,\"bitRate\":140}}');
AgoraRtcEngine.joinChannel(null, widget.channelName, null, 0);
}
/// Create agora sdk instance and initialze
Future<void> _initAgoraRtcEngine() async {
AgoraRtcEngine.create(APP_ID);
AgoraRtcEngine.enableVideo();
}
/// Add agora event handlers
void _addAgoraEventHandlers() {
AgoraRtcEngine.onError = (dynamic code) {
setState(() {
String info = 'onError: ' + code.toString();
_infoStrings.add(info);
});
};
AgoraRtcEngine.onJoinChannelSuccess =
(String channel, int uid, int elapsed) {
setState(() {
String info = 'onJoinChannel: ' + channel + ', uid: ' + uid.toString();
_infoStrings.add(info);
});
};
AgoraRtcEngine.onLeaveChannel = () {
setState(() {
_infoStrings.add('onLeaveChannel');
_users.clear();
});
};
AgoraRtcEngine.onUserJoined = (int uid, int elapsed) {
setState(() {
String info = 'userJoined: ' + uid.toString();
_infoStrings.add(info);
_users.add(uid);
});
};
AgoraRtcEngine.onUserOffline = (int uid, int reason) {
setState(() {
String info = 'userOffline: ' + uid.toString();
_infoStrings.add(info);
_users.remove(uid);
});
};
AgoraRtcEngine.onFirstRemoteVideoFrame =
(int uid, int width, int height, int elapsed) {
setState(() {
String info = 'firstRemoteVideo: ' +
uid.toString() +
' ' +
width.toString() +
'x' +
height.toString();
_infoStrings.add(info);
});
};
}
/// Helper function to get list of native views
List<Widget> _getRenderViews() {
List<Widget> list = [AgoraRenderWidget(0, local: true, preview: true)];
_users.forEach((int uid) => {
list.add(AgoraRenderWidget(uid))
});
return list;
}
/// Video view wrapper
Widget _videoView(view) {
return Expanded(child: Container(child: view));
}
/// Video view row wrapper
Widget _expandedVideoRow(List<Widget> views) {
List<Widget> wrappedViews =
views.map((Widget view) => _videoView(view)).toList();
return Expanded(
child: Row(
children: wrappedViews,
));
}
/// Video layout wrapper
Widget _viewRows() {
List<Widget> views = _getRenderViews();
switch (views.length) {
case 1:
return Container(
child: Column(
children: <Widget>[_videoView(views[0])],
));
case 2:
return Container(
child: Column(
children: <Widget>[
_expandedVideoRow([views[0]]),
_expandedVideoRow([views[1]])
],
));
case 3:
return Container(
child: Column(
children: <Widget>[
_expandedVideoRow(views.sublist(0, 2)),
_expandedVideoRow(views.sublist(2, 3))
],
));
case 4:
return Container(
child: Column(
children: <Widget>[
_expandedVideoRow(views.sublist(0, 2)),
_expandedVideoRow(views.sublist(2, 4))
],
));
default:
}
return Container();
}
/// Toolbar layout
Widget _toolbar() {
return Container(
alignment: Alignment.bottomCenter,
padding: EdgeInsets.symmetric(vertical: 48),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RawMaterialButton(
onPressed: () => _onToggleMute(),
child: new Icon(
muted ? Icons.mic : Icons.mic_off,
color: muted ? Colors.white : Colors.blueAccent,
size: 20.0,
),
shape: new CircleBorder(),
elevation: 2.0,
fillColor: muted ? Colors.blueAccent : Colors.white,
padding: const EdgeInsets.all(12.0),
),
RawMaterialButton(
onPressed: () => _onCallEnd(context),
child: new Icon(
Icons.call_end,
color: Colors.white,
size: 35.0,
),
shape: new CircleBorder(),
elevation: 2.0,
fillColor: Colors.redAccent,
padding: const EdgeInsets.all(15.0),
),
RawMaterialButton(
onPressed: () => _onSwitchCamera(),
child: new Icon(
Icons.switch_camera,
color: Colors.blueAccent,
size: 20.0,
),
shape: new CircleBorder(),
elevation: 2.0,
fillColor: Colors.white,
padding: const EdgeInsets.all(12.0),
)
],
),
);
}
/// Info panel to show logs
Widget _panel() {
return Container(
padding: EdgeInsets.symmetric(vertical: 48),
alignment: Alignment.bottomCenter,
child: FractionallySizedBox(
heightFactor: 0.5,
child: Container(
padding: EdgeInsets.symmetric(vertical: 48),
child: ListView.builder(
reverse: true,
itemCount: _infoStrings.length,
itemBuilder: (BuildContext context, int index) {
if (_infoStrings.length == 0) {
return null;
}
return Padding(
padding:
EdgeInsets.symmetric(vertical: 3, horizontal: 10),
child: Row(mainAxisSize: MainAxisSize.min, children: [
Flexible(
child: Container(
padding: EdgeInsets.symmetric(
vertical: 2, horizontal: 5),
decoration: BoxDecoration(
color: Colors.yellowAccent,
borderRadius: BorderRadius.circular(5)),
child: Text(_infoStrings[index],
style:
TextStyle(color: Colors.blueGrey))))
]));
})),
));
}
void _onCallEnd(BuildContext context) {
Navigator.pop(context);
}
void _onToggleMute() {
setState(() {
muted = !muted;
});
AgoraRtcEngine.muteLocalAudioStream(muted);
}
void _onSwitchCamera() {
AgoraRtcEngine.switchCamera();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Agora Flutter QuickStart'),
),
backgroundColor: Colors.black,
body: Center(
child: Stack(
children: <Widget>[_viewRows(), _panel(), _toolbar()],
)));
}
}
你能看的懂吧。。。然后你能跑起来把。先体验下:
我们下面来分析下。
可以支持4个人同时通话。
我的博客当前情况:
更多推荐
所有评论(0)