I have a Flutter newsreader app that uses a WordPress JSON feed for its content. Im using Advanced Ads Wordpress plugin and its injecting the same ads that are on the web into the JSON Feed with the post content.
When my WebView loads it automatically spawns an external browser. This is without user interaction. The ads are loading fine in the webview. I had the same issue with youtube but applying the same solution to the google ads URL does not work.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
import 'data.dart'; // Post model
import 'html.dart'; // For building HTML content
import 'package:share_plus/share_plus.dart'; // Import share_plus
class PostDetailScreen extends StatefulWidget {
final Post post;
final List<Post> recentPosts;
const PostDetailScreen({Key? key, required this.post, required this.recentPosts}) : super(key: key);
@override
PostDetailScreenState createState() => PostDetailScreenState();
}
class PostDetailScreenState extends State<PostDetailScreen> {
late WebViewController _controller;
String htmlContent = '';
bool isLoading = true;
@override
void initState() {
super.initState();
loadContent();
}
Future<void> loadContent() async {
String encodedVisbyFont = await loadEncodedFont();
String encodedCanelaFont = await loadCanelaFont();
htmlContent = buildHtmlContent(
widget.post.imageUrl,
widget.post.title,
widget.post.content,
widget.post.author,
widget.post.modified,
encodedVisbyFont,
encodedCanelaFont,
widget.recentPosts.take(10).toList()
);
setState(() {
isLoading = false;
});
}
Future<void> updatePostContent(String postLink) async {
final selectedPost = widget.recentPosts.firstWhere(
(post) => post.link == postLink,
orElse: () => widget.post,
);
String updatedContent = buildHtmlContent(
selectedPost.imageUrl,
selectedPost.title,
selectedPost.content,
selectedPost.author,
selectedPost.modified,
await loadEncodedFont(),
await loadCanelaFont(),
widget.recentPosts.take(10).toList(),
);
setState(() {
htmlContent = updatedContent;
});
_controller.loadUrl(Uri.dataFromString(
htmlContent,
mimeType: 'text/html',
encoding: Encoding.getByName('utf-8'),
).toString());
}
@override
Widget build(BuildContext context) {
final bool tablet = MediaQuery.of(context).size.width > 600;
final double titleFontSize = tablet ? 36.0 : 24.0;
final double iconSize = tablet ? 36.0 : 30.0;
final EdgeInsetsGeometry iconPadding = tablet ? const EdgeInsets.all(12.0) : const EdgeInsets.all(8.0);
final double appBarHeight = tablet ? 70.0 : 56.0;
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(appBarHeight),
child: AppBar(
title: Text(
'FRENCHLY',
style: TextStyle(
fontFamily: 'Oswald',
fontSize: titleFontSize,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
backgroundColor: const Color(0xFF1D5986),
centerTitle: true,
iconTheme: IconThemeData(color: Colors.white, size: iconSize),
actions: <Widget>[
Padding(
padding: iconPadding,
child: IconButton(
icon: Icon(Icons.share, color: Colors.white, size: iconSize),
onPressed: () {
Share.share('${widget.post.title}\n\n${widget.post.link}');
},
),
),
],
),
),
body: isLoading
? const Center(child: CircularProgressIndicator())
: WebView(
initialUrl: Uri.dataFromString(
htmlContent,
mimeType: 'text/html',
encoding: Encoding.getByName('utf-8'),
).toString(),
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController controller) {
_controller = controller;
},
navigationDelegate: (NavigationRequest request) async {
if (request.url.startsWith('post://')) {
final postLink = Uri.decodeFull(request.url.substring(7));
updatePostContent(postLink);
return NavigationDecision.prevent;
} else if (request.url.contains('youtube.com') || request.url.contains('youtu.be')) {
// Load YouTube URLs in the WebView itself
return NavigationDecision.navigate;
} else if (await canLaunchUrl(Uri.parse(request.url))) {
await launchUrl(Uri.parse(request.url), mode: LaunchMode.externalApplication);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
);
}
}
This ened up working for me: