前言

继上一篇使用Flutter开发的抖音国际版 后再次撸一个国内版抖音,大部分功能已完成,主要是Flutter开发APP速度很爽,  先看下图

项目主要结构介绍

这次主要的改动在api.dart 及douyin.dart里,国内抖音的api是不同的,另外地址以及实体类也不一样。详细下面介绍.

抖音的实体类

主要是讲json转化为实体模型,然后绑定到view 层面,写这个实体类还是很耗费时间的,毕竟得先用爬网知识讲抖音的json拿到,并且根据json反向写实体类.

这个地址获取到抖音的推荐列表json: https://creator.douyin.com/aweme/v1/creator/data/billboard/?billboard_type=4,绑定第一个Douyin实体,拿到所有抖音的url地址
 
通过第二个api地址 https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids= 拿到抖音视频所有的json信息并且绑定VideoData实体类
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手撸一个抖音国内版,看看有多炫的更多相关文章

  1. 第四篇-用Flutter手撸一个抖音国内版,看看有多炫

    前言 这次对布局进行优化,主要包含了首页tabview pageview 以及添加几个按钮的操作过程.主要使用到stack层叠布局,tabpview和pageview,tabview两个页面,一个关注 ...

  2. 第三篇-用Flutter手撸一个抖音国内版,看看有多炫

    前言 前一篇已经开发了大部分框架,包含视频上下滑动播放,这次将上次未完成的数据显示友好显示,以及底部音乐走马灯特效,另外优化了加载数据的bug,在dart语言里 & 会自动变成&  另 ...

  3. 第五篇- 抖音的强大对手来了,用Flutter手撸一个抖音国际版,看看有多炫

    前言 由于中间几个月项目天天加班,导致没没时间更新,最近一段时间对前端进行了重构,加了很多页面,如登录.注册.关注.个人中心等,目前写这个纯属业余个人爱好,所以断断续续的继续在做...... 前端地址 ...

  4. Golang:手撸一个支持六种级别的日志库

    Golang标准日志库提供的日志输出方法有Print.Fatal.Panic等,没有常见的Debug.Info.Error等日志级别,用起来不太顺手.这篇文章就来手撸一个自己的日志库,可以记录不同级别 ...

  5. 使用Flutter开发的抖音国际版

    简介 最近花了两天时间研究使用Flutter开发一个抖音国际版. 先上图,个人感觉使用Flutter开发app快得不要不要的额.  两天就基本可以开发个大概出来.   最主要是热更新,太方便实时调整U ...

  6. 使用Java Socket手撸一个http服务器

    原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomc ...

  7. 五分钟,手撸一个Spring容器!

    大家好,我是老三,Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开S ...

  8. 【手撸一个ORM】MyOrm的使用说明

    [手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...

  9. 通过 Netty、ZooKeeper 手撸一个 RPC 服务

    说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...

随机推荐

  1. Shoutem旨在成为React Native移动应用领域的WordPress

    近日,Shoutem推出了新的基于React Native的应用构建器,为开发人员提供了移动应用领域的WordPress. \\ Shoutem让开发人员可以使用一个可视化环境快速创建基于React ...

  2. STL训练 HDU - 1716 Ray又对数字的列产生了兴趣:

    HDU - 1716 Ray又对数字的列产生了兴趣: 现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数. Input 每组数据占一行,代表四张卡片上的数字(0&l ...

  3. golang之reflect

    reflect,反射. 利用reflect,可以得到一个struct的相关信息. package main import ( "fmt" "reflect" ) ...

  4. 无线脉冲水表LoRaWAN方案芯片ASR6500S

    无线脉冲水表LoRaWAN方案 物联网是新一代信息技术的重要组成部分,也是"信息化"时代的重要发展阶段,在物联网飞速发展的今天,只有多技术融合的物联网解决方案才能够在不同的应用场景 ...

  5. php接口开发经验总结

    接口开发采用jwt方式验证: 接口开发最好留多几个返回方式,方便本地调用: 待更新.............

  6. DHCP报文(1)

    DHCP报文 1.地址申请类型(4步工作原理,常考) (1)此题是典型的四步工作原理,在其配置过程中由于没有分配IP地址,用的是广播形式,所以其4中报文类型的目的IP地址均为255.255.255.2 ...

  7. 【Spark】SparkStreaming和Kafka的整合

    文章目录 Streaming和Kafka整合 概述 使用0.8版本下Receiver DStream接收数据进行消费 步骤 一.启动Kafka集群 二.创建maven工程,导入jar包 三.创建一个k ...

  8. Day_09【常用API】扩展案例6_将用户给定的字符串首个字符大写,并分别加上"set"和"get"输出

    定义如下方法public static String getPropertyGetMethodName(String property) (1)该方法的参数为String类型,表示用户给定的成员变量的 ...

  9. pyhanlp安装成功,import导入失败,出现:importerror: cannot import name 'jvmnotfoundexception'

    1.问题描述: pyhanlp成功安装,并且可以正常使用,但是这段时间再去用的时候,发现出问题了,一运行就出现,下面的问题: importerror: cannot import name 'jvmn ...

  10. 【FreeRTOS学习02】源码结构/数据类型/命名规则总结

    个人不是很喜欢FreeRTOS的编程风格,但是没办法,白嫖人家的东西,只能忍了,这里先简单总结一下: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 ...