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');
Related
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();
}
}
Since there is no package to implement AdSense in Flutter, I decided to create a local plugin. It's extremely simple, the widget is an IFrameElement. I made sure when creating the plugin to specify that it only supports web because IFrameElement requires import 'dart:html' but whenever I try to compile/build the mobile version it fails because it tries to use the plugin with dart:html. How can I fix this?
Plugin:
import 'dart:html' as html show window;
import 'dart:html';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'adsense_platform_interface.dart';
/// A web implementation of the AdsensePlatform of the Adsense plugin.
class AdsenseWeb extends AdsensePlatform {
/// Constructs a AdsenseWeb
AdsenseWeb();
static void registerWith(Registrar registrar) {
AdsensePlatform.instance = AdsenseWeb();
}
Widget adsenseAdsView(double width, double height) {
ui.platformViewRegistry.registerViewFactory(
'adViewBlock',
(int viewID) => IFrameElement()
..width = '${width.toInt()}'
..height = '${width.toInt()}'
..src = 'adview.html'
..style.border = 'none');
return SizedBox(
height: height,
width: width,
child: const HtmlElementView(
viewType: 'adViewBlock',
),
);
}
/// Returns a [String] containing the version of the platform.
#override
Future<String?> getPlatformVersion() async {
final version = html.window.navigator.userAgent;
return version;
}
}
Use:
import 'package:adsense/adsense_web.dart' show AdsenseWeb;
Widget mainBody() {
final height = MediaQuery.of(context).size.height;
final width = MediaQuery.of(context).size.width;
if (kIsWeb) {
if (height > width) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
locationsGridView(),
AdsenseWeb().adsenseAdsView(width/3, height/2)
],
);
} else {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
locationsGridView(),
AdsenseWeb().adsenseAdsView(width/3, height/2)
],
);
}
} else {
return locationsGridView();
}
}
You must create three classes:
A class for the Flutter Web. This is your current AdsenseWeb class, which contains import 'dart:html'. You can name the file adsense_web.dart.
The class for the mobile build. It should also be called AdsenseWeb. The file can be called adsense_web_stub.dart. There should be no dart:html import in this file! The class could be a stub or have specific behavior for mobile platforms.
A wrapper that selects the desired AdsenseWeb:
import 'package:......adsense_web_stub.dart'
if (dart.library.html) 'package:...... adsense_web.dart'
if (dart.library.io) 'package:...... adsense_web_stub.dart'
as web;
import 'package:flutter/widgets.dart';
class Adsense extends StatelessWidget {
#override
Widget build(BuildContext context) {
return web.AdsenseWeb();
}
}
I am needing to encrypt a hive box, in which the box 'user_api' is to be called in Api_Page_() to receive user input to store inside said box. However, the encryptedBox is not defined within the class. The Hive Docs display the encryption code is to be done inside of the main() function, which I have done, but I am unsure of how to take the box outside of main().
Any help or advice is greatly appreciated!
My Code:
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// HIVE ENCRYPTION----------------------------------------
const secureStorage = FlutterSecureStorage();
final encryptionKey = await secureStorage.read(key: 'key');
if (encryptionKey == null) {
final key = Hive.generateSecureKey();
await secureStorage.write(
key: 'key',
value: base64Encode(key),
);
}
final key = await secureStorage.read(key: 'key');
final encryptKey = base64Url.decode(key);
print('Encryption key: $encryptKey');
// HIVE ENCRYPTION----------------------------------------
// HIVE INIT---------------------------------------------
Directory directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path);
await Hive.initFlutter();
final encryptedBox = Hive.openBox<String>('user_api', encryptionCipher: HiveAesCipher(encryptKey)); // Initially Opens Box on App Start
// HIVE INIT---------------------------------------------
runApp(myApp());
}
class myApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false, // Removes Debug Banner. [Delete before app release]
title: 'App Title Placeholder',
home: API_Page_() // Calls API_Page_ class from api_page.dart
);
}
}
class API_Page_ extends StatelessWidget {
const API_Page_({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: RaisedButton(onPressed: () { var eBox = encryptedBox<String>('user_api');
},
)
);
}
}
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");
}
}
am new to Flutter development, and this might be a naive question, but i was following the beginner tutorial on flutter dev site, and my listview is not showing. I have changed some class/function names,and put the code in different files, but am not sure what is being wrong here, This is supposed to be a list of infinite list of random words.
Here is the complete code:
//File name: main.dart
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app_as/StatefulWidgetStates.dart';
class StatefulRandomWordsWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return RandomWordsState();
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
var wordWidget = StatefulRandomWordsWidget();
return MaterialApp(
title: 'Useless Title',
home: Scaffold(
appBar: AppBar(title: Text('Welcome to Flutter')),
body: wordWidget));
}
}
void main() {
runApp(MyApp());
}
and
//File name: StatefulWidgetStates.dart
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app_as/main.dart';
class RandomWordsState extends State<StatefulRandomWordsWidget> {
final dataList = <WordPair>[];
#override
Widget build(BuildContext context) {
return getListView();
}
Widget getListView() {
ListView listViewWidget = ListView.builder(
itemCount: dataList.length,
padding: EdgeInsets.all(8.0),
itemBuilder: (context, pos) {
if (pos.isOdd) {
return Divider();
}
else {
final index = pos ~/ 2;
if (index >= dataList.length) {
List<WordPair> pairs=generateWordPairs().take(10);
dataList.addAll(pairs);
}
WordPair childData = dataList[index];
return ListTile(title: Text(childData.asCamelCase, style: TextStyle(fontSize: 12.0)));
}
});
return listViewWidget;
}
}
I also don't understand whats this final index = pos ~/ 2; logic about. The official docs say:
The expression i ~/ 2 divides i by 2 and returns an integer result. For example: 1, 2, 3, 4, 5 becomes 0, 1, 1, 2, 2. This calculates the actual number of word pairings in the ListView, minus the divider widgets.
But am guessing am using it wrong.
Remember that when you are working with StateFul Widgets, you need to tell the framework that some state(date) in that widget has changed and it needs to be rebuild. So when you are adding thing to te list, the state changes and it needs to be re-builded. You tell the framework to rebuild by calling the setState((){
}); method.
example:
List<WordPair> pairs = generateWordPairs().take(10);
dataList.addAll(pairs);
setState(() {});