pubspec.yaml : add flushbar dependencie | lib : delete HomeLog.dart, add endi.dart (start only if deeplink is clicked), add bloc.dart (manage deeplink fonctionnality) | ios/Runner/info.plist : add endi URIs | android/app/src/main/AndroidManifest.xml : add endi URIs | android/app/src/main/kotlin/fr.astrolabe.astronote_app/MainActivity.kt : update to manage deeplink fonctionnality

This commit is contained in:
Emeline G 2020-07-23 20:15:44 +02:00
parent 4576c7898b
commit 355b71d775
7 changed files with 188 additions and 61 deletions

View File

@ -1,6 +1,69 @@
package fr.astrolabe.astronote_app package fr.astrolabe.astronote_app
import android.content.BroadcastReceiver
import android.os.Bundle
import android.content.Context
import android.content.Intent
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.EventChannel.EventSink
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() { class MainActivity : FlutterActivity() {
private val CHANNEL = "https://demo.endi.coop"
private val EVENTS = "https://demo.endi.coop/login?nextpage=%2F"
private var startString: String? = null
private var linksReceiver: BroadcastReceiver? = null
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "initialLink") {
if (startString != null) {
result.success(startString)
}
}
}
EventChannel(flutterEngine.dartExecutor, EVENTS).setStreamHandler(
object : EventChannel.StreamHandler {
override fun onListen(args: Any?, events: EventSink) {
linksReceiver = createChangeReceiver(events)
}
override fun onCancel(args: Any?) {
linksReceiver = null
}
}
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = getIntent()
startString = intent.data?.toString()
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
if (intent.action === Intent.ACTION_VIEW) {
linksReceiver?.onReceive(this.applicationContext, intent)
}
}
fun createChangeReceiver(events: EventSink): BroadcastReceiver? {
return object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { // assuming intent.getAction() is Intent.ACTION_VIEW
val dataString = intent.dataString
?: events.error("UNAVAILABLE", "Link unavailable", null)
events.success(dataString)
}
}
}
} }

View File

@ -41,5 +41,9 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:demo.endi.coop</string>
</array>
</dict> </dict>
</plist> </plist>

48
lib/bloc.dart Normal file
View File

@ -0,0 +1,48 @@
import 'dart:async';
import 'package:flutter/services.dart';
abstract class Bloc {
void dispose();
}
class DeepLinkBloc extends Bloc {
//Event Channel creation
static const stream =
const EventChannel('https://demo.endi.coop/login?nextpage=%2F');
//Method channel creation
static const platform = const MethodChannel('https://demo.endi.coop');
StreamController<String> _stateController = StreamController();
Stream<String> get state => _stateController.stream;
Sink<String> get stateSink => _stateController.sink;
//Adding the listener into contructor
DeepLinkBloc() {
//Checking application start by deep link
startUri().then(_onRedirected);
//Checking broadcast stream, if deep link was clicked in opened appication
stream.receiveBroadcastStream().listen((d) => _onRedirected(d));
}
_onRedirected(String uri) {
// Throw deep link URI into the BloC's stream
stateSink.add(uri);
}
@override
void dispose() {
_stateController.close();
}
Future<String> startUri() async {
try {
return platform.invokeMethod('initialLink');
} on PlatformException catch (e) {
return "Failed to Invoke: '${e.message}'.";
}
}
}

View File

@ -1,48 +1,57 @@
import 'package:provider/provider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'bloc.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:flushbar/flushbar.dart';
class HomeLog extends StatefulWidget { class EndiLog extends StatefulWidget {
@override @override
_HomeLogState createState() => _HomeLogState(); _EndiLogState createState() => _EndiLogState();
} }
class _HomeLogState extends State<HomeLog> { class _EndiLogState extends State<EndiLog> {
TextStyle style = TextStyle(fontFamily: 'Varela Round', fontSize: 20.0); TextStyle style = TextStyle(fontFamily: 'Varela Round', fontSize: 20.0);
final GlobalKey<ScaffoldState> _globalKey = GlobalKey<ScaffoldState>();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( DeepLinkBloc _bloc = Provider.of<DeepLinkBloc>(context);
key: _globalKey, return StreamBuilder<String>(
body: SingleChildScrollView( stream: _bloc.state,
child: Container( builder: (context, snapshot) {
height: MediaQuery.of(context).size.height, if (!snapshot.hasData) {
color: Colors.white, return Container(
child: Padding( child: Center(child: Text('No deep link was used ')));
padding: EdgeInsets.all(50), } else {
child: Column( return SingleChildScrollView(
children: <Widget>[ child: Container(
SizedBox(height: 40), height: MediaQuery.of(context).size.height,
_logoApp(), color: Colors.white,
_titleApp(), child: Padding(
SizedBox(height: 90), padding: EdgeInsets.all(50),
_emailField(), child: Column(
SizedBox(height: 30), children: <Widget>[
_passwordField(), // SizedBox(height: 40),
SizedBox(height: 50), _logoApp(),
_logButton(), _titleApp(),
SizedBox(height: 70), SizedBox(height: 80),
_enDIUrl(), _emailField(),
SizedBox(height: 10), SizedBox(height: 30),
_astrolabeUrl() _passwordField(),
], SizedBox(height: 50),
), _logButton(),
), SizedBox(height: 70),
), _enDIUrl(),
), SizedBox(height: 5),
); _astrolabeUrl()
],
),
),
),
);
}
});
} }
Widget _logoApp() { Widget _logoApp() {
return SizedBox( return SizedBox(
height: 100.0, height: 100.0,
@ -67,7 +76,7 @@ class _HomeLogState extends State<HomeLog> {
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0), contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
labelText: "E-mail", labelText: "E-mail",
border: border:
OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))), OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))),
); );
} }
@ -79,7 +88,7 @@ class _HomeLogState extends State<HomeLog> {
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0), contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
labelText: "Mot de passe", labelText: "Mot de passe",
border: border:
OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))), OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))),
); );
} }
@ -99,18 +108,22 @@ class _HomeLogState extends State<HomeLog> {
)); ));
} }
void showErrorFlushbar(BuildContext context) {
Flushbar(
message: "Impossible d'ouvrir le lien",
backgroundColor: Colors.red[300],
duration: Duration(seconds: 3),
// Show it with a cascading operator
)..show(context);
}
void _launchLinkEnDI() async { void _launchLinkEnDI() async {
const url = "https://endi.coop"; const url = "https://endi.coop";
if (await canLaunch(url)) { if (await canLaunch(url)) {
await launch(url); await launch(url);
} else { } else {
final snack = SnackBar( showErrorFlushbar(context);
content: Text("Impossible de lancer le lien"),
duration: Duration(seconds: 4),
backgroundColor: Colors.red[300],
);
_globalKey.currentState.showSnackBar(snack);
} }
} }
@ -120,12 +133,7 @@ class _HomeLogState extends State<HomeLog> {
if (await canLaunch(url)) { if (await canLaunch(url)) {
await launch(url); await launch(url);
} else { } else {
final snack = SnackBar( showErrorFlushbar(context);
content: Text("Impossible de lancer le lien"),
duration: Duration(seconds: 4),
backgroundColor: Colors.red[300],
);
_globalKey.currentState.showSnackBar(snack);
} }
} }
@ -154,5 +162,4 @@ class _HomeLogState extends State<HomeLog> {
), ),
); );
} }
} }

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'views/HomeLog.dart'; import 'bloc.dart';
import 'package:provider/provider.dart';
import 'endi.dart';
void main() => runApp(MyApp()); void main() => runApp(MyApp());
@ -7,11 +9,14 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application. // This widget is the root of your application.
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
DeepLinkBloc _bloc = DeepLinkBloc();
return MaterialApp( return MaterialApp(
home: HomeLog(), debugShowCheckedModeBanner: false,
debugShowCheckedModeBanner: false, home: Scaffold(
); body: Provider<DeepLinkBloc>(
create: (context) => _bloc,
dispose: (context, bloc) => bloc.dispose(),
child: EndiLog())));
} }
} }

View File

@ -64,13 +64,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.3" version: "0.1.3"
email_validator: flushbar:
dependency: "direct main" dependency: "direct main"
description: description:
name: email_validator name: flushbar
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.5" version: "1.10.4"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -267,5 +267,5 @@ packages:
source: hosted source: hosted
version: "3.6.1" version: "3.6.1"
sdks: sdks:
dart: ">=2.7.0 <3.0.0" dart: ">=2.7.2 <3.0.0"
flutter: ">=1.16.0 <2.0.0" flutter: ">=1.16.0 <2.0.0"

View File

@ -24,7 +24,7 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
provider: ^4.3.1 provider: ^4.3.1
email_validator: '^1.0.0' flushbar: ^1.10.4
url_launcher: ^5.5.0 url_launcher: ^5.5.0
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.