I created a fixed display ad 320px *60px. How do I insert in flutter web where I want?
This is the code I obtained from adsense:
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- MyAd -->
<ins class="adsbygoogle"
style="display:inline-block;width:320px;height:60px"
data-ad-client="xxxxxxxxx"
data-ad-slot="xxxxxxxx"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
Or is it possible to make flutter not occupy the bottom 60 pixels of the screen and insert the adsense ad there by manipulating flt-glass-pane somehow?
I'm looking at a way to insert adsense ads to a mobile website built in flutter-web
I was able to insert ads into the listview in flutter-web as below:
Created an html file adview.html
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
style="display:inline-block;width:320px;height:80px"
data-ad-client="ca-pub-xxxxxx"
data-ad-slot="xxxxxxx"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
And then, an IFrameElement to make use of the html:
// ignore: avoid_web_libraries_in_flutter
import 'dart:html';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
Widget adsenseAdsView() {
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'adViewType',
(int viewID) => IFrameElement()
..width = '320'
..height = '100'
..src = 'adview.html'
..style.border = 'none');
return SizedBox(
height: 100.0,
width: 320.0,
child: HtmlElementView(
viewType: 'adViewType',
),
);
}
Then we can add the widget from the function adsenseAdsView() wherever we want. I added it in ListView.
There is a new package that can help with this. Hopefully makes the process a little simpler.
https://pub.dev/packages/admanager_web
Example to implement:
AdBlock(
size: AdBlockSize.largeRectangle,
adUnitId: "/6355419/Travel/Europe",)
You can add Adsense ad unit In Flutter Web with the help of below widget. It's work perfectly fine.
create widget with any name you like. I'm name BannerAdUnit
only replace div tag ad unit id and script add Url as you can see in the below widget inside html body tag.
import 'dart:html' as html;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
String viewID = "your-view-id";
class BannerAdUnit extends StatelessWidget {
const BannerAdUnit({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
ui.platformViewRegistry.registerViewFactory(
viewID,
(int id) => html.IFrameElement()
..style.width = '100%'
..style.height = '100%'
..srcdoc = '''
<!DOCTYPE html>
<html> <head> </head> <body>
<div data-frill-widget="your ad unit id will come here" style="width: 340px; height: 460px;"></div>
<script async src="url"></script> </body>
</html> '''
..style.border = 'none');
return SizedBox(
height: 460,
width: 340,
child: HtmlElementView(
viewType: viewID,
),
);
}
}
The story is not end here. When you add the above code You will see one beautiful error something like that.
The name 'platformViewRegistry' is being referenced through the prefix
'ui', but it isn't defined in any of the libraries imported using that
prefix. (Documentation)
How to fix this error? Don't worry I'll show you how to fix this error.
Create new file on the root name it analysis_options.yaml
and copy and paste the below code and the error is gone.
analyzer:
errors:
undefined_prefixed_name: ignore
Note: On the debugging mode flutter Web app not show you any ads.
if you want to see ads deploy your Flutter Web App. you will see ads like this.
If you guys don't want to write these spaghetti code try this package flutter_ad_manager_web. I created this helpful package for display Adsense ads on Flutter Web.
Related
In my web enabled flutter app, To add media query I have added css class in body tag in index.html file.
<head>
....
<style>
.mobile{
max-width:auto;
}
#media (min-width: 600px) {
.mobile{
max-width:400px;
}
}
</style>
</head>
<body class="mobile">
<script src="main.dart.js" type="application/javascript"></script>
</body>
But flutter here is creating flt-glass-pane tag inside the body tag and it is rendering UI overflowing the body tag.
In my second approach, I have to add MediaQuery at screen level, but I don't want to add media query in each scaffold/screen.
So is there any alternative so that I could apply media query in MateriaApp or in index.html file only once.
Use "builder" in Material App
MaterialApp(
...
...
builder: (context, child) {
double screenWidth = MediaQuery.of(context).size.width;
return Center(
child: Container(
width: screenWidth > 600 ? 400 : screenWidth,
child: child,
),
);
},
);
I have built a video calling app in Flutter using the Agora SDK. This is only available for iOS/Android and so for the web build I had to build a wrapper around the existing Agora web SDK. Due to the way Flutter renders web elements inside a shadow DOM, you cannot access elements by document.getElementById(), which is what the Agora SDK uses to inject their video player. To get around this I am rendering an IFrame that has the div and Agora SDK script bundled together.
It is all working nicely but when any event is triggered inside the browser window, such as the mouse entering a button or clicking anything, the IFrame refreshes and rebuilds the video view which takes 1-2 seconds to initialize.
Is there anyway I can unlink the IFrame from the browser events? I tried marking the HtmlElementView as const and putting it inside a StatefulWidget that only registers the platform view once. The widget isn't actually running the build() method again but the IFrame still refreshes.
Flutter code
ui.platformViewRegistry.registerViewFactory(
'video-container',
(int viewId) => IFrameElement()
..id = 'my-iframe'
..width = '100%'
..height = '100%'
..src = 'assets/web_elements/agora_container.html'
..allow = "camera; microphone"
..style.border = 'none');
#override
Widget build(BuildContext context) {
print("*****\n\n\nBuilding the web host container\n\n\n*****"); // this is only printing once
return const HtmlElementView(
viewType: 'video-container',
);
}
Agora code
<div id="local-video"></div>
<div id="remote-video"></div>
<div id="video-canvas"></div>
<script src="scripts/AgoraSDK.js"></script>
<script src="scripts/agora_controller.js"></script>
What worked for me was this:
Key key = UniqueKey(); // before the build method
HtmlElementView(
key: key,
viewType: 'iframeElement',
);
Now there is no rebuilding/rerunning. Note I am using the iframeElement, not video-container, but this should work. Please comment.
This is one of the active problem with the Flutter Web. I guess a workaround to this is mentioned here: https://github.com/flutter/flutter/issues/53253#issuecomment-607197549
I am trying to implement the reCaptcha function to my flutter app, but in the captcha registration I need to provide a domain which I don't have one for a mobile app. I have browsed several guides teaching how to implement reCaptcha into a mobile app, yet those guides registered their reCaptcha with package names but not domains. What is the correct way to implement reCaptcha in a flutter app, or any mobile app in 2020?
You can use this plugin, flutter_recaptcha.
For the domain, I had the same issue. I first found that I needed to use the "I'm not a robot" checkbox option from here and I had to check the github repository to find this information, "!!! Remember to add this domain into the reCaptcha setting: recaptcha-flutter-plugin.firebaseapp.com," which explains it.
I was lost for a bit after not seeing that on the main page, but now it makes sense. Hopefully it helps.
Edit
I noticed something after trying it out, that I'd like to mention. The plugin does not provide a captcha response for using to authenticate the user server-side, so it does not seem very useful as it is. However, it is a simple plugin, so it may be possible to use it as an example. The steps, I think, would be to create a webpage with the captcha. As with the plugin, use a webview to open the page, then capture the post output of the form and ip address of user submitting the form, using something like this, then send it to flutter and then submit your request with that information, and use the Google library to verify the captcha.
Instructions
I just finished implementing this and I found a good way that works.
First, create an html page, like this:
<html>
<head>
<title>reCAPTCHA</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body style='background-color: aqua;'>
<div style='height: 60px;'></div>
<form action="?" method="POST">
<div class="g-recaptcha"
data-sitekey="YOUR-SITE-KEY"
data-callback="captchaCallback"></div>
</form>
<script>
function captchaCallback(response){
//console.log(response);
if(typeof Captcha!=="undefined"){
Captcha.postMessage(response);
}
}
</script>
</body>
</html>
Then, host that on your domain, say example.com/captcha.
Then, create a flutter Widget, like this:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class Captcha extends StatefulWidget{
Function callback;
Captcha(this.callback);
#override
State<StatefulWidget> createState() {
return CaptchaState();
}
}
class CaptchaState extends State<Captcha>{
WebViewController webViewController;
#override
initState(){
super.initState();
}
#override
Widget build(BuildContext context) {
return Center(
child: WebView(
initialUrl: "https://example.com/captcha.html",
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: Set.from([
JavascriptChannel(
name: 'Captcha',
onMessageReceived: (JavascriptMessage message) {
//This is where you receive message from
//javascript code and handle in Flutter/Dart
//like here, the message is just being printed
//in Run/LogCat window of android studio
//print(message.message);
widget.callback(message.message);
Navigator.of(context).pop();
})
]),
onWebViewCreated: (WebViewController w) {
webViewController = w;
},
)
);
}
}
Make sure you registered for a captcha key at https://www.google.com/recaptcha (click on "Admin Console" at the top-right).
Then, you have the front-end built. To call a captcha, just run:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context){
return Captcha((String code)=>print("Code returned: "+code));
}
),
);
You can use whatever callback you want to, like this:
class GenericState extends State<Generic>{
void methodWithCaptcha(String captchaCode){
// Do something with captchaCode
}
#override
Widget build(BuildContext context) {
return Center(child:FlatButton(
child: Text("Click here!"),
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (context){
return Captcha(methodWithCaptcha);
}
),
);
}
}
}
Server-side, you can follow the instructions here (I followed the sections "Direct Download" and "Usage"). I found that for the usage, I could simply use the code:
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);
if ($resp->isSuccess()) {
// Verified!
} else {
$errors = $resp->getErrorCodes();
}
Using setExpectedHostname, like in the example, was unnecessary.
After that, everything works! I think this is currently the best way to implement Google reCaptcha V2 in flutter (for both iOS and Android).
If you are looking for Flutter WEB, You can try g_recaptcha_v3 package
Note:
it supports reCAPTCHA V3 only and not V2
its for Flutter Web only and no other platform supports
I've improved #JVE999 approach and created a new package:
flutter_firebase_recaptcha
The package uses InAppWebView for recapcha HTML rendering, so you don't need separate web page anymore.
My widget supports 'visible' and 'invisible' recapcha. Invisible recapcha allows you try to get recapcha token without showing anything to your user.
UPDATE (2021/05/11):
Flutter now natively has Hover Events implemented Widgets.
There is a MouseCursor for Widgets like RaisedButton and properties like hoverColor or hoverElevation.
https://api.flutter.dev/flutter/services/MouseCursor-class.html
You can also use an InkWell anywhere else as stated in the accepted answer.
Original Question:
How can the cursor appearance be changed within Flutter?
I know that with the Listener() Widget we can listen for Mouse-Events,
but I haven't found any information regarding hovering events for flutter web.
Has someone found a soulution yet?
I had difficulties finding documentation on the now built-in support. Here is what helped me: https://github.com/flutter/flutter/issues/58260
And this did the trick for me, without changing index.html etc.
MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Icon(
Icons.add_comment,
size: 20,
),
onTap: () {},
),
),
Also see the official documentation: https://api.flutter.dev/flutter/rendering/MouseCursor-class.html
Widget build(BuildContext context) {
return Center(
child: MouseRegion(
cursor: SystemMouseCursors.text,
child: Container(
width: 200,
height: 100,
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(color: Colors.yellow),
),
),
),
);
}
And here https://api.flutter.dev/flutter/material/MaterialStateMouseCursor-class.html yet another wonderful example from the official docs that "...defines a mouse cursor that resolves to SystemMouseCursors.forbidden when its widget is disabled."
Starting with dev channel build version 1.19.0–3.0.pre there is built-in support for the pointer cursor. The same method as bellow is used with the difference that is applied to the Flutter app container element flt-glass-pane. Using the bellow method will just duplicate the behavior.
In order to override the pointer cursor, you can use the bellow method but applied on the flt-glass-pane element.
A workaround for this is the following:
You have to set an id (for example app-container on the entire body of the app's index.html template).
This is how your index.html will look like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My awesome app</title>
</head>
<body id="app-container">
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
Next, you have to create a wrapper dart class. I called it hand_cursor.dart:
import 'package:flutter_web/gestures.dart';
import 'package:flutter_web/widgets.dart';
import 'package:universal_html/html.dart' as html;
// see https://pub.dev/packages/universal_html
class HandCursor extends MouseRegion {
// get a reference to the body element that we previously altered
static final appContainer = html.window.document.getElementById('app-container');
HandCursor({Widget child}) : super(
onHover: (PointerHoverEvent evt) {
appContainer.style.cursor='pointer';
// you can use any of these:
// 'help', 'wait', 'move', 'crosshair', 'text' or 'pointer'
// more options/details here: http://www.javascripter.net/faq/stylesc.htm
},
onExit: (PointerExitEvent evt) {
// set cursor's style 'default' to return it to the original state
appContainer.style.cursor='default';
},
child: child
);
}
After that, wherever you want to have the hand cursor shown, you have to wrap your element in this HandCursor wrapper. See the class awesome_button.dart bellow:
import 'package:awesome_app/widgets/containers/hand_cursor.dart';
import 'package:flutter_web/material.dart';
import 'package:flutter_web/widgets.dart';
class AwesomeButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
HandCursor(
child: IconButton(
onPressed: () {
// do some magic
},
icon: Icon(Icons.star)
),
)
],
);
}
}
A short explanation can be found here.
A more versatile update, that works on the new web projects created with the master channel of Flutter, can be found here.
I hope it helps.
You can use an InkWell that has an onHover event
InkWell(
onTap: () {},
onHover: (value) {
setState(() {
isHovered = value;
});
},
child: Container(
width: 50,
height: 72,
color: Colors.black
)
);
Make sure to have something onTap, even an empty function, else it is considered to be disabled, and the hover won't work
The previous method is deprecated. Here is the updated code
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import 'package:universal_html/prefer_sdk/html.dart' as html;
class HandCursor extends MouseRegion {
static final appContainer = html.window.document.getElementById('app-container');
HandCursor({Widget child})
: super(
onHover: (PointerHoverEvent evt) {
appContainer.style.cursor = 'pointer';
},
onExit: (PointerExitEvent evt) {
appContainer.style.cursor = 'default';
},
child: child,
);
}
And in your pubspec.yaml file, add universal_html as a package as a dependency. The version may change.
dependencies:
flutter:
sdk: flutter
universal_html: ^1.1.4
You still want to have an id of app-container attached to the body of your html. Here is my html file.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Your App Title</title>
</head>
<body id="app-container">
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
You want to put the code for the HandCursor widget in its own file. You can call it hand_cursor.dart. And to use it on the widget you want the hand to show up on, import it into the file you're working on and wrap the widget you want in the HandCursor widget.
From Flutter beta version 1.19.0-4.1.pre, add id to body and set cursor of that doesn't work. Because flt-glass-pane is replacing the cursor.
So the solution is that set cursor directly to flt-glass-pane.
Below is the update that is working.
class HandCursor extends MouseRegion {
static final appContainer = html.window.document.querySelectorAll('flt-glass-pane')[0];
HandCursor({Widget child}) : super(
onHover: (PointerHoverEvent evt) {
appContainer.style.cursor='pointer';
},
onExit: (PointerExitEvent evt) {
appContainer.style.cursor='default';
},
child: child
);
}
final appContainer
= html.document.getElementsByTagName('body')[0] as html.Element;
GestureDetector(
child: MouseRegion(
child: Text(
'https://github.com/yumi0629',
style: textStyle,
),
onHover: (_) => appContainer.style.cursor = 'pointer',
onExit: (_) => appContainer.style.cursor = 'default',
),
onTap: () {
print('open');
js.context.callMethod(
'open', ['https://github.com/yumi0629']);
},
)
The most easy way what i know
InkWell(
onTap: (){},
mouseCursor: MaterialStateMouseCursor.clickable,
...
I believe that mouse events won't work on the web, Listener Widget was demoed on Google I/O 2019 and worked with mouse, but that was as a ChromeOS app and not a web app.
According to Flutter web on GitHub:
At this time, desktop UI interactions are not fully complete, so a UI built with flutter_web may feel like a mobile app, even when running on a desktop browser.
Adapted answer by Constantin Stan
For those who want to have the click effect similar to InkWell widget and with border radius option:
Add to your pubspec.yaml file
dependencies:
universal_html: ^1.1.4
Then add to the index.html file the following the tag <body id="app-container"> as below:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Your App Title</title>
</head>
<body id="app-container">
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
Finally create the following widget and use encapsulated all the necessary widgets:
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:universal_html/prefer_sdk/html.dart' as html;
class InkWellMouseRegion extends InkWell {
InkWellMouseRegion({
Key key,
#required Widget child,
#required GestureTapCallback onTap,
double borderRadius = 0,
}) : super(
key: key,
child: !kIsWeb ? child : HoverAware(child: child),
onTap: onTap,
borderRadius: BorderRadius.circular(borderRadius),
);
}
class HoverAware extends MouseRegion {
// get a reference to the body element that we previously altered
static final appContainer = html.window.document.getElementById('app-container');
HoverAware({Widget child}) : super(
onHover: (PointerHoverEvent evt) {
appContainer.style.cursor='pointer';
// you can use any of these:
// 'help', 'wait', 'move', 'crosshair', 'text' or 'pointer'
// more options/details here: http://www.javascripter.net/faq/stylesc.htm
},
onExit: (PointerExitEvent evt) {
// set cursor's style 'default' to return it to the original state
appContainer.style.cursor='default';
},
child: child
);
}
I would like to play youtube video or launch to the youtube url but I can't find a way because if you use url_launcher or video_player, flutter web won't be able to run and it says you can't run with flutter SDK.
So is there any way I can let user see the video?
I've detailed here a solution that uses the Afterglow video player.
The Afterglow video player supports playing YouTube videos (and even Vimeo videos), so it will serve your case.
Basically you need to alter the index.html template file and interact with the DOM using either dart:html or universal_html packages to get your desired video playing. You'll need to know the video id of the YouTube video you want to play.
index.html will look like:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Web YouTube Video Player</title>
<script src="https://cdn.jsdelivr.net/npm/afterglowplayer#1.x"></script></head>
<body>
<script src="main.dart.js" type="application/javascript"></script>
<a id="triggerYouTubeVideoPlayer" class="afterglow" href="#videoPlayer"></a>
<video id="youTubeVideoPlayer" width="960" height="540" data-skin="dark">
</video>
</body>
</html>
You'll need a playYouTubeVideo method like the following:
import 'package:flutter/foundation.dart';
import 'package:universal_html/html.dart' as html;
void playYouTubeVideo(String withId) {
if(kIsWeb) {
final v = html.window.document.getElementById('youTubeVideoPlayer');
if(v != null) {
v.setAttribute("data-youtube-id", withId);
final a = html.window.document.getElementById( 'triggerYouTubeVideoPlayer' );
if(a != null) {
a.dispatchEvent(html.MouseEvent('click'));
}
}
} else {
// we're not on the web platform
// and should use the video_player package
}
}
And you'll play the video like this:
playYouTubeVideo('5jidaSuRVKw');
You can replace this with any HTML/JS video player of your choice, the approach would be the same.
Before the 10th of December 2019, this method was one of the only ways of playing videos in a Flutter web app. At Flutter Interact 2019 the web support for a couple of packages, including the video_player_web package. The option presented above still work and may serve you better in your use case.
check out this example here:
HTML PLATFORM VIEW example
void main() {
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => IFrameElement()
..width = '640'
..height = '360'
..src = 'https://www.youtube.com/embed/IyFZznAk69U'
..style.border = 'none');
runApp(Directionality(
textDirection: TextDirection.ltr,
child: SizedBox(
width: 640,
height: 360,
child: HtmlElementView(viewType: 'hello-world-html'),
),
));
}
I found a way to open the link but I still don't know how to play video.
I guess I should wait it to become stable.
import 'dart:html' as html;
onPressed: () {
html.window.open('https://stackoverflow.com/', 'Dummy');
}
Post Merge To Main Flutter library
I struggled with this for a while but currently you should be using the 'dart:ui' library instead of the flutter_for_web_ui version. This still gives an error which you should ignore and run anyway.
import 'dart:ui' as ui;
void main() {
ui.platformViewRegistry.registerViewFactory( // platformViewRegistry will show as error
'hello-world-html',
(int viewId) => IFrameElement()
..width = '640'
..height = '360'
..src = 'https://www.youtube.com/embed/IyFZznAk69U'
..style.border = 'none');
runApp(Directionality(
textDirection: TextDirection.ltr,
child: SizedBox(
width: 640,
height: 360,
child: HtmlElementView(viewType: 'hello-world-html'),
),
));
}
Here is the referenced issue ui.platformViewRegistry issue