当你将链接复制到WhatsApp对话中时,会显示一个缩略图和目标页面的几行。当你在Facebook上发布链接时,也是一样的。
对于任何类型的链接,他们如何总是找到缩略图来显示?只要目标页面上有图像就行!
我想在我的Flutter应用程序中做同样的事情。我已经设法显示这样的YouTube缩略图:
import 'package:youtube_parser/youtube_parser.dart' as yt;
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<String> getFutureYoutubeThumbnailUrl(String userDefinedLink) async {
String? thumbnailUrl;
String? videoId = yt.getIdFromUrl(userDefinedLink);
if (videoId != null) {
http.Response? res;
try {
res = await http.get(Uri.parse('https://www.googleapis.com/youtube/v3/videos?id=$videoId&key=$googleApiKey&part=snippet'));
} catch (e) {
print('Error getting YouTube snippet: $e');
}
if (res != null) {
print('res.body is ${res.body}');
Map<String, dynamic> decodedResponse = jsonDecode(res.body);
thumbnailUrl = decodedResponse['items'][0]['snippet']['thumbnails']['default']['url'];
}
}
print('thumbnailUrl is $thumbnailUrl');
return thumbnailUrl ?? '';
}
然后我显示URL一旦它准备好了:Image(image: NetworkImage(thumbnailUrl))
.
但这需要非常具体的知识,关于在哪里找到缩略图URL从非常具体的YouTube API调用的响应!如果我甚至不知道是否这是一个YouTube链接或其他类型的链接吗?我是否需要为我能想到的每种类型的链接提供量身定制的解决方案?Facebook和WhatsApp就是这么做的吗?🤔
有没有一些方便的即插即用的解决方案,可以在网上找到,或者什么?🙂
后续qn:现在,你告诉我一个颤振包,这很好。但我想知道:是否有更通用的、独立于语言的解决方案来做到这一点?比如API调用?如果是这样,我该如何编写这个API调用?
首先对Facebook的例子进行解释。大多数社交网络都通过Facebook元标签提供这类信息。
Facebook图片的键例如:
<meta property="og:image" content="http://ia.media-imdb.com/rock.jpg"/>
<meta property="og:image:secure_url" content="https://secure.example.com/ogp.jpg" /
其他平台也在使用同样的方式,因为它对所有类型的网站都很重要,现在他们有一个博客,或者正在使用SEO。所以这是典型的。
对于颤振的使用你不需要关心别人分享的来源。如果源中没有提供图像,则只需要一个占位符。使用这个包,例如
You can run this example and try it out on yourself:
import 'package:any_link_preview/any_link_preview.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
/// I picked these links & images from internet
final String _errorImage =
"https://i.ytimg.com/vi/z8wrRRR7_qU/maxresdefault.jpg";
final String _url1 =
"https://www.espn.in/football/soccer-transfers/story/4163866/transfer-talk-lionel-messi-tells-barcelona-hes-more-likely-to-leave-then-stay";
final String _url2 =
"https://speakerdeck.com/themsaid/the-power-of-laravel-queues";
final String _url3 =
"https://twitter.com/laravelphp/status/1222535498880692225";
final String _url4 = "https://www.youtube.com/watch?v=W1pNjxmNHNQ";
final String _url5 = "https://www.brainyquote.com/topics/motivational-quotes";
@override
void initState() {
super.initState();
_getMetadata(_url5);
}
void _getMetadata(String url) async {
bool _isValid = _getUrlValid(url);
if (_isValid) {
Metadata? _metadata = await AnyLinkPreview.getMetadata(
link: url,
cache: Duration(days: 7),
proxyUrl: "https://cors-anywhere.herokuapp.com/", // Needed for web app
);
debugPrint(_metadata?.title);
debugPrint(_metadata?.desc);
} else {
debugPrint("URL is not valid");
}
}
bool _getUrlValid(String url) {
bool _isUrlValid = AnyLinkPreview.isValidLink(
url,
protocols: ['http', 'https'],
hostWhitelist: ['https://youtube.com/'],
hostBlacklist: ['https://facebook.com/'],
);
return _isUrlValid;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Any Link Preview')),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnyLinkPreview(
link: _url1,
displayDirection: UIDirection.uiDirectionHorizontal,
cache: Duration(hours: 1),
backgroundColor: Colors.grey[300],
errorWidget: Container(
color: Colors.grey[300],
child: Text('Oops!'),
),
errorImage: _errorImage,
),
SizedBox(height: 25),
AnyLinkPreview(
link: _url2,
displayDirection: UIDirection.uiDirectionHorizontal,
showMultimedia: false,
bodyMaxLines: 5,
bodyTextOverflow: TextOverflow.ellipsis,
titleStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15,
),
bodyStyle: TextStyle(color: Colors.grey, fontSize: 12),
),
SizedBox(height: 25),
AnyLinkPreview(
displayDirection: UIDirection.uiDirectionHorizontal,
link: _url3,
errorBody: 'Show my custom error body',
errorTitle: 'Next one is youtube link, error title',
),
SizedBox(height: 25),
AnyLinkPreview(link: _url4),
],
),
),
),
);
}
}
如果没有图片可以提供,你也可以从文档中生成一个自定义占位符。
占位符,可以在状态正在加载时使用。
这就是我的意思。这里提供了接收这些图像源的所有重要技术。HTML解析器适用于所有类型的网站,opengraph twitter适用于所有大型社交媒体平台。
HTML解析器,JSON LD解析器,开放图谱解析器,Twitter卡片解析器未来还会有更多。