Flutter web: run Js method from flutter page - flutter

I have Stripe WebGl Gradient Animation on my flutter web project, I put this file inside assets folder.
In my stateful widget, I made an I frame and set everything I guess it needs.
import 'dart:html';
import 'dart:ui' as ui;
import 'dart:js' as js;
late Widget _iframeWidget;
final IFrameElement _iframeElement = IFrameElement();
#override
void initState() {
super.initState();
_iframeElement.height = double.maxFinite.toString();
_iframeElement.width = double.maxFinite.toString();
_iframeElement.allowFullscreen = true;
_iframeElement.style.border = 'none';
_iframeElement.id = 'iframe';
_iframeElement.src = 'assets/gradient.html';
_iframeElement.style.border = 'none';
final wrapper = DivElement()
..style.width = '100%'
..style.height = '100%';
wrapper.append(_iframeElement);
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'iframeElement',
(int viewId) => _iframeElement,
);
_iframeWidget = HtmlElementView(
key: UniqueKey(),
viewType: 'iframeElement',
);
}
inside gradient.html there are some js methods to play and stop animation, Now How can I call these methods from Flutter?
I don't want to use webview.

Related

Trying to implement AdSense in Flutter Web - TagError: adsbygoogle.push() error: No slot size for availableWidth=0

I have a Flutter app that uses AdMob but that doesn't work for web. As suggested by some solutions, I am trying to use an IFrame to display an AdSense ad. I have almost the same code as one example that worked for others, but for me, it does not show the ad and I get an error TagError: adsbygoogle.push() error: No slot size for availableWidth=0. Is there a better way to go about this? If not, what part of my code is causing the error?
adview.html:
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-<replace>"
crossorigin="anonymous"></script>
<!-- Web Flutter Globe -->
<ins class="adsbygoogle"
style="display:inline-block;width:320px;height:80px"
data-ad-client="ca-pub-<replace>"
data-ad-slot="<replace>"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
adview.dart:
import 'mobile_implementation.dart'
if (dart.library.html) 'web_implementation.dart'
as package;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
class AdsenseWeb extends StatelessWidget {
const AdsenseWeb({super.key, required this.height, required this.width});
final double height;
final double width;
#override
Widget build(BuildContext context) {
return kIsWeb
? package.AdsenseWeb.adsenseAdsView(width, height)
: const SizedBox();
}
}
web_implementation.dart:
import 'dart:html';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
class AdsenseWeb {
static Widget adsenseAdsView(double width, double height) {
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'adViewType',
(int viewID) => IFrameElement()
..width = '$width'
..height = '$height'
..src = 'adview.html'
..style.border = 'none');
return SizedBox(
height: height,
width: width,
child: const HtmlElementView(
viewType: 'adViewType',
),
);
}
}
mobile_implementation.dart:
import 'package:flutter/material.dart';
class AdsenseWeb {
static Widget adsenseAdsView(double width, double height) {
return const SizedBox();
}
}

Flutter Iframe freezing on page reload

I have a widget page which lets me edit the source of an iframe. This works fine, but when I leave the page and return, my iframe becomes stuck in the state that it was when I initially left the page and then cant be edited.
Although the iframes src is changing on in the flutter code, it doesn't actually render the new src, again only rendering the old one. I've been stuck trying to fix this for a while and have no clue why its not working, so help is very appreciated. Thanks.
final IFrameElement _iframeElement = IFrameElement();
#override
void initState() {
super.initState();
print('INITIALAISING');
widthValueController.addListener(_setValueWidth);
heightValueController.addListener(_setValueHeight);
data = 'CarbTreePlas';
_iframeElement.src =
'/assets/lib/company_widget/widget-site/widget.html?slug=${widget.slug}&layout=box&data=$data';
_iframeElement.attributes['frameBorder'] = '0';
_iframeElement.attributes['scrolling'] = 'no';
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'iframeElement',
(int viewId) => _iframeElement,
);
widgetCode =
'<iframe frameBorder = "0" Scrolling = "0" width="$currValueWidth" height="$currValueHeight" src=${_iframeElement.src} />';
}
Container(
color: Colors.white,
height: currValueHeight,
width: currValueWidth,
child: HtmlElementView(
key: UniqueKey(),
viewType: 'iframeElement',
),
),

I get an IllegalStateException sometimes in flutter app after adding native ads to a listview

this is the error I get:
setState() called after dispose(): _PlatformViewLinkState#bc2a5(lifecycle state: defunct, not mounted)
This error happens if you...
E/flutter ( 4758): [ERROR:flutter/shell/platform/android/platform_view_android_jni_impl.cc(49)] java.lang.IllegalStateException: PlatformView#getView() returned null, but an Android view reference was expected.
I'm using the google_mobile_ads package and not the firebase_ads one since it's deprecated.
I'm trying to put native ads in a list of cards, after a fixed number of elements in the listview.
The way I did this is by using a provider in the main.dart file:
...
void main() {
WidgetsFlutterBinding.ensureInitialized();
final initFuture = MobileAds.instance.initialize();
final adState = AdState(initFuture);
runApp(Provider.value(
value: adState,
builder: (context, child) => MyApp(),
));
}
...
the screen containing the listview is called chapters_screen.dart, when going to this screen the app sometimes crashes. In this file there is a list of items List<Object> itemList = []; as a state variable. In init state the list is populated with offline data as so: itemList = List.from(chaptersData);,
this is how I add the ads in the list:
#override
void didChangeDependencies() {
super.didChangeDependencies();
final adState = Provider.of<AdState>(context);
if(this.mounted){
adState.initialization.then((status) {
if(this.mounted){
setState(() {
for (int i = itemList.length - 2; i >= 1; i -= 2) {
itemList.insert(
i,
// BannerAd(
// adUnitId: adState.bannerAdUnitId,
// size: AdSize.banner,
// request: AdRequest(),
// listener: adState.adListener,
// )..load(),
NativeAd(
adUnitId: adState.nativeAdUnitId,
factoryId: 'listTile',
request: AdRequest(),
listener: NativeAdListener(
onAdLoaded: (_) {
print('ad is loaded succesfully!');
},
onAdFailedToLoad: (ad, error) {
// Releases an ad resource when it fails to load
ad.dispose();
print('Ad load failed (code=${error.code} message=${error.message})'); },
),
)..load(),
);
}
});
}
});
}
}
I tried it before with a banner ad and there is no problem. I followed this tutorial: https://www.youtube.com/watch?v=m0d_pbgeeG8 but I had to change the google_mobile_ads package version to a newer one to be able to use the same NativeAdFactory as in the flutter documentation. The problem is in the newer version the AdListener object no longer exists so instead of passing: listener: adState.adListener like in the video. I put the listener as the code above in the 'NativeAd()' widget.
this is how I'm checking for the type of the listItem to build it in the listView:
Widget _buildListView(BuildContext context) {
List<Widget> widgetList = [];
for (int i = 0; i < itemList.length; i++) {
if (itemList[i] is NativeAd) {
widgetList.add(Container(
height: 200,
child: AdWidget(ad: itemList[i] as NativeAd),
color: Colors.black));
} else {
widgetList.add(ChapterCard(chapter: Chapter.fromJson(itemList[i])));
}
}
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/blured_background.jpg"),
fit: BoxFit.cover,
),
),
child: ListView(children: widgetList.toList()),
);
}
I think I'm doing something wrong in the provider or in the factory class but I'm not sure.
the factory class for android (in java):
import com.google.android.gms.ads.nativead.NativeAd;
import com.google.android.gms.ads.nativead.NativeAdView;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Map;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;
class ListTileNativeAdFactory implements GoogleMobileAdsPlugin.NativeAdFactory {
private final Context context;
ListTileNativeAdFactory(Context context) {
this.context = context;
}
#Override
public NativeAdView createNativeAd(
NativeAd nativeAd, Map<String, Object> customOptions) {
NativeAdView nativeAdView = (NativeAdView) LayoutInflater.from(context)
.inflate(R.layout.list_tile_native_ad, null);
TextView attributionViewSmall = nativeAdView
.findViewById(R.id.tv_list_tile_native_ad_attribution_small);
TextView attributionViewLarge = nativeAdView
.findViewById(R.id.tv_list_tile_native_ad_attribution_large);
ImageView iconView = nativeAdView.findViewById(R.id.iv_list_tile_native_ad_icon);
NativeAd.Image icon = nativeAd.getIcon();
if (icon != null) {
attributionViewSmall.setVisibility(View.VISIBLE);
attributionViewLarge.setVisibility(View.INVISIBLE);
iconView.setImageDrawable(icon.getDrawable());
} else {
attributionViewSmall.setVisibility(View.INVISIBLE);
attributionViewLarge.setVisibility(View.VISIBLE);
}
nativeAdView.setIconView(iconView);
TextView headlineView = nativeAdView.findViewById(R.id.tv_list_tile_native_ad_headline);
headlineView.setText(nativeAd.getHeadline());
nativeAdView.setHeadlineView(headlineView);
TextView bodyView = nativeAdView.findViewById(R.id.tv_list_tile_native_ad_body);
bodyView.setText(nativeAd.getBody());
bodyView.setVisibility(nativeAd.getBody() != null ? View.VISIBLE : View.INVISIBLE);
nativeAdView.setBodyView(bodyView);
nativeAdView.setNativeAd(nativeAd);
return nativeAdView;
}
}
The MainActivity class:
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;
public class MainActivity extends FlutterActivity {
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
// TODO: Register the ListTileNativeAdFactory
GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine, "listTile",
new ListTileNativeAdFactory(getContext()));
}
#Override
public void cleanUpFlutterEngine(#NonNull FlutterEngine flutterEngine) {
super.cleanUpFlutterEngine(flutterEngine);
// TODO: Unregister the ListTileNativeAdFactory
GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "listTile");
}
}

How to prevent error of platformViewRegistry [flutter-web]

I am trying to add pdf view in my web page (flutter web).. here is part of the code
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => html.IFrameElement()
..width = '700'
..height = '4000'
..src = 'http:xxx.pdf'
..style.border = 'none');
the code runs like what I want, but I get error like this
The name 'platformViewRegistry' is being referenced through the prefix 'ui', but it isn't defined in any of the libraries imported using that prefix.
Try correcting the prefix or importing the library that defines 'platformViewRegistry'.
is there a way to prevent that error happen?
Edit use analysis_options.yaml
analyzer:
errors:
undefined_prefixed_name: ignore
You can copy paste run full code below
You can use // ignore: undefined_prefixed_name
code snippet
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => html.IFrameElement()
..width = '700'
..height = '4000'
..src = 'http:xxx.pdf'
..style.border = 'none');
working demo
full simulate code
import 'package:flutter/material.dart';
// import 'dart:io' if (dart.library.html) 'dart:ui' as ui;
import 'dart:ui' as ui;
import 'dart:html' as html;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Iframe()),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class Iframe extends StatelessWidget {
Iframe() {
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory('iframe', (int viewId) {
var iframe = html.IFrameElement();
iframe.src = 'http://www.africau.edu/images/default/sample.pdf';
return iframe;
});
}
#override
Widget build(BuildContext context) {
return Container(
width: 400, height: 300, child: HtmlElementView(viewType: 'iframe'));
}
}
chunhunghan's proposed fix of ignoring undefined_prefix_name is overkill and risky. If you do this, all errors of the type prefix.wrongValue will be suppressed in your IDE. If you're on a small/personal project, this is fine, but if you're working on a larger scale project I would advise against this.
A better solution is to create a shim file for not-web contexts like so:
platform_view_registry.dart
export 'package:my_package/src/fake_platform_view_registry.dart'
if (dart.library.html) 'dart:ui' show platformViewRegistry;
fake_platform_view_registry.dart
// add either a dynamically typed variable
dynamic platformViewRegistry;
// or a more thorough shim like this one
class FakePlatformViewRegistry {
void registerViewFactory(
String viewTypeId, dynamic Function(int) viewFactory) {
throw UnsupportedError("platform view registry in non-web context");
}
}
final platformViewRegistry = FakePlatformViewRegistry();
Then just import package:my_package/src/platform_view_registry.dart instead of dart:ui (and probably drop the ui prefix too).
import "package:my_package/src/platform_view_registry.dart";
...
platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => html.IFrameElement()
..width = '700'
..height = '4000'
..src = 'http:xxx.pdf'
..style.border = 'none');

Flutter Web, HtmlElementView, "Removing disallowed attribute"

I am trying to Create HtmlElementView for Playstore Application Badge in Flutter Web?
I tried the following as mentioned here
Widget _getAppStoreBadgeView() {
final NodeValidatorBuilder _htmlValidator =
new NodeValidatorBuilder.common()
..allowElement('a', attributes: ['data-target', 'data-toggle'])
..allowElement('button', attributes: ['data-target', 'data-toggle']);
ui.platformViewRegistry.registerViewFactory("idid", (int viewId) {
final element = DivElement()
..setInnerHtml(r"""
<a href='https://play.google.com/store/apps/details?id=com.shahxad.evendor&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/></a>
""", validator: _htmlValidator)
..style.width = "100%"
..style.height = "100%"
..style.border = 'none';
return element;
});
return Container(
child: HtmlElementView(viewType: "idid"),
height: 150,
width: 400,
);
}
But it's not working as I am getting like this.
I am getting this message in the Chrome console.
Removing disallowed attribute
html_dart2js.dart:39901 Removing disallowed attribute <A href="https://play.google.com/store/apps/details?id=com.shahxad.flutter_tex_example&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1">
html_dart2js.dart:39901 Removing disallowed attribute <IMG src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png">
Use NodeValidatorBuilder from the dart:html library with predefined rules allowHtml5, allowNavigation, allowImages and define class ItemUrlPolicy to allow navigation from generated html-code.
import 'dart:html' as html;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
class ItemUrlPolicy implements html.UriPolicy {
RegExp regex = RegExp(r'(?:http://|https://)?.*');
bool allowsUri(String uri) {
return regex.hasMatch(uri);
}
}
class MyWidget extends StatefulWidget {
#override
MyWidgetState createState() => MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
html.DivElement _element;
#override
void initState() {
super.initState();
_element = html.DivElement()
..appendHtml("""
<a href='https://play.google.com/store/apps/details?id=com.shahxad.evendor&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'>
<img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/>
</a>
""",
validator: html.NodeValidatorBuilder()
..allowHtml5(uriPolicy: ItemUrlPolicy())
..allowNavigation(ItemUrlPolicy())
..allowImages(ItemUrlPolicy()));
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory('demo-view', (int viewId) => _element);
}
#override
Widget build(BuildContext context) {
return HtmlElementView(key: UniqueKey(), viewType: "demo-view");
}
}