第二篇-用Flutter手撸一个抖音国内版,看看有多炫
前言
继上一篇使用Flutter开发的抖音国际版 后再次撸一个国内版抖音,大部分功能已完成,主要是Flutter开发APP速度很爽, 先看下图
项目主要结构介绍
这次主要的改动在api.dart 及douyin.dart里,国内抖音的api是不同的,另外地址以及实体类也不一样。详细下面介绍.
抖音的实体类
主要是讲json转化为实体模型,然后绑定到view 层面,写这个实体类还是很耗费时间的,毕竟得先用爬网知识讲抖音的json拿到,并且根据json反向写实体类.
class Douyin {
int statusCode;
String statusMsg;
List<BillboardData> billboardData;
Extra extra; Douyin({this.statusCode, this.statusMsg, this.billboardData, this.extra}); Douyin.fromJson(Map<String, dynamic> json) {
statusCode = json["status_code"];
statusMsg = json["status_msg"];
if (json['billboard_data'] != null) {
billboardData = new List<BillboardData>();
json["billboard_data"].forEach((v) {
billboardData.add(BillboardData.fromJson(v));
});
}
extra = json['extra'] != null ? new Extra.fromJson(json['extra']) : null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["status_code"] = this.statusCode;
data["status_msg"] = this.statusMsg;
if (this.billboardData != null) {
data["billboard_data"] =
this.billboardData.map((v) => v.toJson()).toList();
}
data["extra"] = this.extra;
return data;
}
} class BillboardData {
String author;
String imgUrl;
String link;
int rank;
String title;
String value; BillboardData(
{this.author, this.imgUrl, this.link, this.rank, this.title, this.value}); BillboardData.fromJson(Map<String, dynamic> json) {
this.author = json["author"];
this.imgUrl = json["img_url"];
this.link = json["link"];
this.rank = json["rank"];
this.title = json["title"];
this.value = json["value"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["author"] = this.author;
data["img_url"] = this.imgUrl;
data["link"] = this.link;
data["rank"] = this.rank;
data["title"] = this.title;
data["value"] = this.value;
return data;
}
} class Extra {
int now;
Extra({this.now}); Extra.fromJson(Map<String, dynamic> json) {
now = json["now"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["now"] = this.now;
return data;
}
} class VideoData {
int statusCode;
List<Itemlist> itemList;
ExtraData extra; VideoData.fromJson(Map<String, dynamic> json) {
this.statusCode = json["status_code"];
if (json['item_list'] != null) {
itemList = new List<Itemlist>();
json['item_list'].forEach((v) {
itemList.add(new Itemlist.fromJson(v));
});
}
this.extra =
json["extra"] != null ? new ExtraData.fromJson(json["extra"]) : null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["status_code"] = this.statusCode;
if (this.itemList != null) {
data['item_list'] = this.itemList.map((v) => v.toJson()).toList();
}
if (this.extra != null) {
data["extra"] = this.extra.toJson();
}
return data;
}
} class Itemlist {
String awemeid;
String videolabels;
String labeltoptext;
int category;
Author author;
int duration;
String promotions;
int ispreview;
int createtime;
List<ChaList> chalist;
String commentlist;
int authoruserid;
String videotext;
int groupid;
bool islivereplay;
ShareInfo shareinfo;
String position;
String imageinfos;
RiskInfos riskinfos;
String uniqidposition;
String geofencing;
Statistics statistics;
int awemetype;
Music music;
List<TextExtra> textExtras;
Video video;
String shareurl;
String desc;
String longvideo; Itemlist(
{this.awemeid,
this.videolabels,
this.labeltoptext,
this.category,
this.author,
this.duration,
this.promotions,
this.ispreview,
this.createtime,
this.chalist,
this.commentlist,
this.authoruserid,
this.videotext,
this.groupid,
this.islivereplay,
this.shareinfo,
this.position,
this.imageinfos,
this.riskinfos,
this.uniqidposition,
this.geofencing,
this.statistics,
this.awemetype,
this.music,
this.textExtras,
this.video,
this.shareurl,
this.desc,
this.longvideo}); Itemlist.fromJson(Map<String, dynamic> json) {
this.awemeid = json["aweme_id"];
this.videolabels = json["video_labels"];
this.labeltoptext = json["label_top_text"];
this.category = json["category"];
this.author =
json["author"] != null ? new Author.fromJson(json["author"]) : null;
this.duration = json["duration"];
this.promotions = json["promotions"];
this.ispreview = json["is_preview"];
this.createtime = json["create_time"];
if (json["cha_list"] != null) {
this.chalist = new List<ChaList>();
json["cha_list"].forEach((v) {
this.chalist.add(new ChaList.fromJson(v));
});
}
this.commentlist = json["comment_list"];
this.authoruserid = json["author_user_id"];
this.videotext = json["video_text"];
this.groupid = json["group_id"];
this.islivereplay = json["is_live_replay"];
this.shareinfo = json["share_info"] != null
? new ShareInfo.fromJson(json["share_info"])
: null;
this.position = json["position"];
this.imageinfos = json["image_infos"];
this.riskinfos = json["risk_infos"] != null
? new RiskInfos.fromJson(json["risk_infos"])
: null;
this.uniqidposition = json["uniqid_position"];
this.geofencing = json["geofencing"];
this.statistics = json["statistics"] != null
? new Statistics.fromJson(json["statistics"])
: null;
this.awemetype = json["aweme_type"];
this.music =
json["music"] != null ? new Music.fromJson(json["music"]) : null;
if (json["text_extra"] != null) {
this.textExtras = new List<TextExtra>();
json['text_extra'].forEach((v) {
textExtras.add(new TextExtra.formJson(v));
});
}
this.video =
json["video"] != null ? new Video.fromJson(json["video"]) : null;
this.shareurl = json["share_url"];
this.desc = json["desc"];
this.longvideo = json["long_video"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["aweme_id"] = this.awemeid;
data["video_labels"] = this.videolabels;
data["label_top_text"] = this.labeltoptext;
data["category"] = this.category;
if (this.author != null) {
data["author"] = this.author.toJson();
}
data["duration"] = this.duration;
data["promotions"] = this.promotions;
data["is_preview"] = this.ispreview;
data["create_time"] = this.createtime;
if (this.chalist != null) {
data["cha_list"] = this.chalist.map((e) => e.toJson()).toList();
}
data["comment_list"] = this.commentlist;
data["author_user_id"] = this.authoruserid;
data["video_text"] = this.videotext;
data["group_id"] = this.groupid;
data["is_live_replay"] = this.islivereplay;
if (this.shareinfo != null) {
data["share_info"] = this.shareinfo.toJson();
}
data["position"] = this.position;
data["image_infos"] = this.imageinfos;
if (this.riskinfos != null) {
data["risk_infos"] = this.riskinfos.toJson();
}
data["uniqid_position"] = this.uniqidposition;
data["geofencing"] = this.geofencing;
if (this.statistics != null) {
data["statistics"] = this.statistics.toJson();
}
data["aweme_type"] = this.awemetype;
if (this.music != null) {
data["music"] = this.music.toJson();
}
if (this.textExtras != null) {
data["text_extra"] = this.textExtras.map((e) => e.toJson()).toList();
}
if (this.video != null) {
data["video"] = this.video.toJson();
}
data["share_url"] = this.shareurl;
data["desc"] = this.desc;
data["long_video"] = this.longvideo;
return data;
}
} class TextExtra {
String hashtagName;
int hashtagId;
int start;
int end;
int type; TextExtra(
{this.hashtagName, this.hashtagId, this.start, this.end, this.type}); TextExtra.formJson(Map<String, dynamic> json) {
this.hashtagName = json["hashtag_name"];
this.hashtagId = json["hashtag_id"];
this.start = json["start"];
this.end = json["end"];
this.type = json["type"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["hashtag_name"] = this.hashtagName;
data["hashtag_id"] = this.hashtagId;
data["start"] = this.start;
data["end"] = this.end;
data["type"] = this.type;
return data;
}
} // Author
class Author {
String geofencing;
String uid;
String shortID;
String signature;
AvatarMedium avatarMedium;
String uniqueId;
String followersDetail;
String platformSyncInfo;
String policyVersion;
String nickname;
AvatarLarger avatarlarger;
AvatarThumb avatarthumb; Author(
{this.geofencing,
this.uid,
this.shortID,
this.signature,
this.avatarMedium,
this.uniqueId,
this.followersDetail,
this.platformSyncInfo,
this.policyVersion,
this.nickname,
this.avatarlarger,
this.avatarthumb}); Author.fromJson(Map<String, dynamic> json) {
this.geofencing = json["geofencing"];
this.uid = json["uid"];
this.shortID = json["short_id"];
this.signature = json["signature"];
this.avatarMedium = json["avatar_medium"] != null
? new AvatarMedium.fromJson(json["avatar_medium"])
: null;
this.uniqueId = json["unique_id"];
this.followersDetail = json["followers_detail"];
this.platformSyncInfo = json["platform_sync_info"];
this.policyVersion = json["policy_version"];
this.nickname = json["nickname"];
this.avatarlarger = json["avatar_larger"] != null
? new AvatarLarger.formJson(json["avatar_larger"])
: null;
this.avatarthumb = json["avatar_thumb"] != null
? new AvatarThumb.formJson(json["avatar_thumb"])
: null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["geofencing"] = this.geofencing;
data["uid"] = this.uid;
data["short_id"] = this.shortID;
data["signature"] = this.signature;
if (this.avatarMedium != null) {
data["avatar_medium"] = this.avatarMedium.toJson();
}
data["unique_id"] = this.uniqueId;
data["followers_detail"] = this.followersDetail;
data["platform_sync_info"] = this.platformSyncInfo;
data["policy_version"] = this.policyVersion;
data["nickname"] = this.nickname;
if (this.avatarlarger != null) {
data["avatar_larger"] = this.avatarlarger.toJson();
}
if (this.avatarthumb != null) {
data["avatar_thumb"] = this.avatarthumb.toJson();
}
return data;
}
} class AvatarMedium {
List<String> urlList;
String uri;
AvatarMedium({this.urlList, this.uri}); AvatarMedium.fromJson(Map<String, dynamic> json) {
if (json["url_list"] != null) {
this.urlList = json["url_list"].cast<String>();
}
this.uri = json["uri"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
return data;
}
} class AvatarLarger {
String uri;
List<String> urlList;
AvatarLarger({this.uri, this.urlList}); AvatarLarger.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class AvatarThumb {
String uri;
List<String> urlList;
AvatarThumb({this.uri, this.urlList}); AvatarThumb.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class ExtraData {
int now;
String logid;
ExtraData({this.now, this.logid}); ExtraData.fromJson(Map<String, dynamic> json) {
this.now = json["now"];
this.logid = json["logid"];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["now"] = this.now;
data["logid"] = this.logid;
return data;
}
}
//End author //ChaList
class ChaList {
String chaName;
int viewCount;
String hashTagProfile;
bool isCommerce;
String cid;
String desc;
int userCount;
String connectMusic;
int type;
CoverItem coverItem;
ChaList(
{this.chaName,
this.viewCount,
this.hashTagProfile,
this.isCommerce,
this.cid,
this.desc,
this.userCount,
this.connectMusic,
this.type,
this.coverItem}); ChaList.fromJson(Map<String, dynamic> json) {
this.chaName = json["cha_name"];
this.viewCount = json["view_count"];
this.hashTagProfile = json["hash_tag_profile"];
this.isCommerce = json["is_commerce"];
this.cid = json["cid"];
this.desc = json["desc"];
this.userCount = json["user_count"];
this.connectMusic = json["connect_music"];
this.type = json["type"];
this.coverItem = json["cover_item"] != null
? new CoverItem.formJson(json["cover_item"])
: null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["cha_name"] = this.chaName;
data["view_count"] = this.viewCount;
data["hash_tag_profile"] = this.hashTagProfile;
data["is_commerce"] = this.isCommerce;
data["cid"] = this.cid;
data["desc"] = this.desc;
data["user_count"] = this.userCount;
data["connect_music"] = this.connectMusic;
data["type"] = this.type;
if (this.coverItem != null) {
data["cover_item"] = this.coverItem.toJson();
}
return data;
}
} class CoverItem {
String uri;
List<String> urlList;
CoverItem({this.uri, this.urlList});
CoverItem.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
}
//End ChaList //ShareInfo
class ShareInfo {
String shareweibodesc;
String sharedesc;
String sharetitle;
ShareInfo({this.shareweibodesc, this.sharedesc, this.sharetitle});
ShareInfo.fromJson(Map<String, dynamic> json) {
this.shareweibodesc = json["share_weibo_desc"];
this.sharedesc = json["share_desc"];
this.sharetitle = json["share_title"];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["share_weibo_desc"] = this.shareweibodesc;
data["share_desc"] = this.sharedesc;
data["share_title"] = this.sharetitle;
return data;
}
}
//End ShareInfo //RiskInfos
class RiskInfos {
bool warn;
int type;
String content;
RiskInfos({this.warn, this.type, this.content});
RiskInfos.fromJson(Map<String, dynamic> json) {
this.warn = json["warn"] as bool;
this.type = json["type"];
this.content = json["content"];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["warn"] = this.warn;
data["type"] = this.type;
data["content"] = this.content;
return data;
}
}
//End RiskInfos //Statistics
class Statistics {
String awemeId;
int commentCount;
int diggCount;
Statistics.fromJson(Map<String, dynamic> json) {
this.awemeId = json["aweme_id"];
this.commentCount = json["comment_count"];
this.diggCount = json["digg_count"];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["aweme_id"] = this.awemeId;
data["comment_count"] = this.commentCount;
data["digg_count"] = this.diggCount;
return data;
}
}
//End Statistics //Music
class Music {
CoverLarge coverlarge;
CoverMedium covermedium;
int duration;
int status;
String mid;
String title;
String author;
PlayUrl playurl;
String position;
int id;
CoverHd coverhd;
CoverThumb coverthumb; Music.fromJson(Map<String, dynamic> json) {
this.coverlarge = json["cover_large"] != null
? new CoverLarge.formJson(json["cover_large"])
: null;
this.covermedium = json["cover_medium"] != null
? new CoverMedium.formJson(json["cover_medium"])
: null;
this.duration = json["duration"];
this.status = json["status"];
this.mid = json["mid"];
this.title = json["title"];
this.author = json["author"];
this.playurl = json["play_url"] != null
? new PlayUrl.formJson(json["play_url"])
: null;
this.position = json["position"];
this.id = json["id"];
this.coverhd = json["cover_hd"] != null
? new CoverHd.formJson(json["cover_hd"])
: null;
this.coverthumb = json["cover_thumb"] != null
? new CoverThumb.formJson(json["cover_thumb"])
: null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.coverlarge != null) {
data["cover_large"] = this.coverlarge.toJson();
}
if (this.covermedium != null) {
data["cover_medium"] = this.covermedium.toJson();
}
data["duration"] = this.duration;
data["status"] = this.status;
data["mid"] = this.mid;
data["title"] = this.title;
data["author"] = this.author;
if (this.playurl != null) {
data["play_url"] = this.playurl.toJson();
}
data["position"] = this.position;
data["id"] = this.id;
if (this.coverhd != null) {
data["cover_hd"] = this.coverhd.toJson();
}
if (this.coverthumb != null) {
data["cover_thumb"] = this.coverthumb.toJson();
}
return data;
}
} class CoverLarge {
String uri;
List<String> urlList;
CoverLarge({this.uri, this.urlList});
CoverLarge.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class CoverMedium {
String uri;
List<String> urlList;
CoverMedium({this.uri, this.urlList});
CoverMedium.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class PlayUrl {
String uri;
List<String> urlList;
PlayUrl({this.uri, this.urlList});
PlayUrl.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class CoverHd {
String uri;
List<String> urlList;
CoverHd({this.uri, this.urlList});
CoverHd.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class CoverThumb {
String uri;
List<String> urlList;
CoverThumb({this.uri, this.urlList});
CoverThumb.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
}
//End Music //Video
class Video {
int width;
OriginCover origincover;
String ratio;
bool haswatermark;
String bitrate;
PlayAddr playaddr;
Cover cover;
int duration;
String vid;
int islongvideo;
int height;
DynamicCover dynamiccover;
Video(
{this.width,
this.origincover,
this.ratio,
this.haswatermark,
this.bitrate,
this.playaddr,
this.cover,
this.duration,
this.vid,
this.islongvideo,
this.height,
this.dynamiccover});
Video.fromJson(Map<String, dynamic> json) {
this.width = json["width"];
this.origincover = json["origin_cover"] != null
? new OriginCover.formJson(json["origin_cover"])
: null;
this.ratio = json["ratio"];
this.haswatermark = json["has_watermark"];
this.bitrate = json["bit_rate"];
this.playaddr = json["play_addr"] != null
? new PlayAddr.formJson(json["play_addr"])
: null;
this.cover =
json["cover"] != null ? new Cover.formJson(json["cover"]) : null;
this.duration = json["duration"];
this.vid = json["vid"];
this.islongvideo = json["is_long_video"];
this.height = json["height"];
this.dynamiccover = json["dynamic_cover"] != null
? new DynamicCover.formJson(json["dynamic_cover"])
: null;
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["width"] = this.width;
if (this.origincover != null) {
data["origin_cover"] = this.origincover.toJson();
}
data["ratio"] = this.ratio;
data["has_watermark"] = this.haswatermark;
data["bit_rate"] = this.bitrate;
if (this.playaddr != null) {
data["play_addr"] = this.playaddr.toJson();
}
if (this.cover != null) {
data["cover"] = this.cover.toJson();
}
data["duration"] = this.duration;
data["vid"] = this.vid;
data["is_long_video"] = this.islongvideo;
data["height"] = this.height;
if (this.dynamiccover != null) {
data["dynamic_cover"] = this.dynamiccover.toJson();
}
return data;
}
} class OriginCover {
String uri;
List<String> urlList;
OriginCover({this.uri, this.urlList});
OriginCover.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class PlayAddr {
String uri;
List<String> urlList;
PlayAddr({this.uri, this.urlList});
PlayAddr.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class Cover {
String uri;
List<String> urlList;
Cover({this.uri, this.urlList});
Cover.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} class DynamicCover {
String uri;
List<String> urlList;
DynamicCover({this.uri, this.urlList});
DynamicCover.formJson(Map<String, dynamic> json) {
this.uri = json["uri"] as String;
this.urlList = json["url_list"].cast<String>();
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["url_list"] = this.urlList;
data["uri"] = this.uri;
return data;
}
} //End Video
取抖音无水印视频,这里才是关键
通过这个api地址 https://aweme.snssdk.com/aweme/v1/play/?video_id={}&ratio=720p&line=0&media_type=4&vr_type=0&improve_bitrate=0&is_play_url=1&h265=1&adapt720=1 可以成功的拿到无水印视频,
此方法仅用于学习研究目的,不得从事违法活动哈, 否则与本作者无关.
具体实现代码如下
import 'dart:io'; import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import 'package:dio/dio.dart'; class RequestController {
//static String host = "https://www.tiktok.com/";
static String host = "https://creator.douyin.com";
String url = host + "/aweme/v1/creator/data/billboard/?billboard_type=4"; String video =
"https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids="; String player = "https://aweme.snssdk.com/aweme/v1/play/?video_id="; Future<String> getVideos() async {
try {
var response = await http.get(url);
return response.body;
} catch (e) {
return e.toString();
}
} //获取无水印的视频
Future<String> getRedirects(String videoid) async {
try {
var response = await new Dio().get(
player +
videoid +
"&ratio=720p&line=0&media_type=4&vr_type=0&improve_bitrate=0&is_play_url=1&h265=1&adapt720=1",
options: Options(
headers: headers,
contentType: "text/html; charset=utf-8",
followRedirects: false,
validateStatus: (status) {
return status < 500;
}),
);
if (response.statusCode == 302) {
return response.data.toString().split('"')[1];
}
return '';
} catch (ex) {
return '';
}
} Future<String> getCookie() async {
try {
var response = await http.get(host + "/share/item/");
return response.headers["set-cookie"];
} catch (e) {
return "error";
}
} var headers = {
"user-agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
};
}
剩下就是改造TrendingScreen里获取视频的方法
getTrending() async {
//var cookies = await api.getCookie();
//api.setCookie(cookies);
try {
var response = await http.get(
api.url,
headers: api.headers,
);
Douyin tiktok = Douyin.fromJson(jsonDecode(response.body));
tiktok.billboardData.forEach(
(item) {
setState(() {
getVideos(item);
});
},
);
} catch (ex) {
SimpleDialog(
title: Text('Hot videos list is empty'),
);
print(ex);
}
}
把获取到的无水印视频加载到view层
getVideos(BillboardData v) async {
try {
var url = v.link.split("/")[5];
var response = await http.get(
api.video + url + "&dytk",
headers: api.headers,
);
VideoData videoData = VideoData.fromJson(jsonDecode(response.body));
//获取无水印的视频地址
api.getRedirects(videoData.itemList[0].video.playaddr.uri).then((url) => {
print( Uri.decodeFull(url)),
if (url != '')
{
videos.add(VideoItem(
data: videoData,
videourl: url,
))
}
});
} catch (ex) {
print(ex);
}
}
最后,就是绑定视频数据啦,大功告成!
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
DouyinVideoPlayer(
url: videourl,
),
title(),
VideoDescription(
description: data.itemList[0].textExtras[0].hashtagName,
musicName: data.itemList[0].music.title,
authorName: data.itemList[0].music.author,
userName: data.itemList[0].author.nickname,
),
ActionsToolbar(
comments: data.itemList[0].statistics.commentCount.toString(),
userImg: data.itemList[0].author.avatarMedium.urlList[0],
favorite: data.itemList[0].statistics.diggCount,
coverImg: data.itemList[0].music.covermedium.urlList[0],
),
],
),
);
}
结语
写到这里,手撸一个抖音app完成了基本功能,一些数据转化比喻点赞数还是原始int数据,需要转化成K M 等,后续待完善,毕竟花了一天时间来写这个app纯粹为了兴趣. 本人也极喜欢玩抖音.
另外因为写得匆忙,只测试了少量数据,json返回的数据有些为null ,也不知道具体是啥类型,这个待完善。 各位博友们觉得感兴趣的点个赞哈. 支持支持!
顺便说一下,各位支持的话点赞关注我继续完善剩余的部分,有需要学习了解的可以联系我,代码上传到github ,地址:https://github.com/WangCharlie/douyin,到这里就点个star, 谢谢.
第二篇-用Flutter手撸一个抖音国内版,看看有多炫的更多相关文章
- 第四篇-用Flutter手撸一个抖音国内版,看看有多炫
前言 这次对布局进行优化,主要包含了首页tabview pageview 以及添加几个按钮的操作过程.主要使用到stack层叠布局,tabpview和pageview,tabview两个页面,一个关注 ...
- 第三篇-用Flutter手撸一个抖音国内版,看看有多炫
前言 前一篇已经开发了大部分框架,包含视频上下滑动播放,这次将上次未完成的数据显示友好显示,以及底部音乐走马灯特效,另外优化了加载数据的bug,在dart语言里 & 会自动变成& 另 ...
- 第五篇- 抖音的强大对手来了,用Flutter手撸一个抖音国际版,看看有多炫
前言 由于中间几个月项目天天加班,导致没没时间更新,最近一段时间对前端进行了重构,加了很多页面,如登录.注册.关注.个人中心等,目前写这个纯属业余个人爱好,所以断断续续的继续在做...... 前端地址 ...
- Golang:手撸一个支持六种级别的日志库
Golang标准日志库提供的日志输出方法有Print.Fatal.Panic等,没有常见的Debug.Info.Error等日志级别,用起来不太顺手.这篇文章就来手撸一个自己的日志库,可以记录不同级别 ...
- 使用Flutter开发的抖音国际版
简介 最近花了两天时间研究使用Flutter开发一个抖音国际版. 先上图,个人感觉使用Flutter开发app快得不要不要的额. 两天就基本可以开发个大概出来. 最主要是热更新,太方便实时调整U ...
- 使用Java Socket手撸一个http服务器
原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomc ...
- 五分钟,手撸一个Spring容器!
大家好,我是老三,Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开S ...
- 【手撸一个ORM】MyOrm的使用说明
[手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...
- 通过 Netty、ZooKeeper 手撸一个 RPC 服务
说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...
随机推荐
- Shoutem旨在成为React Native移动应用领域的WordPress
近日,Shoutem推出了新的基于React Native的应用构建器,为开发人员提供了移动应用领域的WordPress. \\ Shoutem让开发人员可以使用一个可视化环境快速创建基于React ...
- STL训练 HDU - 1716 Ray又对数字的列产生了兴趣:
HDU - 1716 Ray又对数字的列产生了兴趣: 现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数. Input 每组数据占一行,代表四张卡片上的数字(0&l ...
- golang之reflect
reflect,反射. 利用reflect,可以得到一个struct的相关信息. package main import ( "fmt" "reflect" ) ...
- 无线脉冲水表LoRaWAN方案芯片ASR6500S
无线脉冲水表LoRaWAN方案 物联网是新一代信息技术的重要组成部分,也是"信息化"时代的重要发展阶段,在物联网飞速发展的今天,只有多技术融合的物联网解决方案才能够在不同的应用场景 ...
- php接口开发经验总结
接口开发采用jwt方式验证: 接口开发最好留多几个返回方式,方便本地调用: 待更新.............
- DHCP报文(1)
DHCP报文 1.地址申请类型(4步工作原理,常考) (1)此题是典型的四步工作原理,在其配置过程中由于没有分配IP地址,用的是广播形式,所以其4中报文类型的目的IP地址均为255.255.255.2 ...
- 【Spark】SparkStreaming和Kafka的整合
文章目录 Streaming和Kafka整合 概述 使用0.8版本下Receiver DStream接收数据进行消费 步骤 一.启动Kafka集群 二.创建maven工程,导入jar包 三.创建一个k ...
- Day_09【常用API】扩展案例6_将用户给定的字符串首个字符大写,并分别加上"set"和"get"输出
定义如下方法public static String getPropertyGetMethodName(String property) (1)该方法的参数为String类型,表示用户给定的成员变量的 ...
- pyhanlp安装成功,import导入失败,出现:importerror: cannot import name 'jvmnotfoundexception'
1.问题描述: pyhanlp成功安装,并且可以正常使用,但是这段时间再去用的时候,发现出问题了,一运行就出现,下面的问题: importerror: cannot import name 'jvmn ...
- 【FreeRTOS学习02】源码结构/数据类型/命名规则总结
个人不是很喜欢FreeRTOS的编程风格,但是没办法,白嫖人家的东西,只能忍了,这里先简单总结一下: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 ...