iOS网络开发-打造自己的视频客户端

时间:2023-03-09 07:30:57
iOS网络开发-打造自己的视频客户端

一.展示实现

效果

iOS网络开发-打造自己的视频客户端    iOS网络开发-打造自己的视频客户端

客户端:                                      服务器端:

iOS网络开发-打造自己的视频客户端          iOS网络开发-打造自己的视频客户端

二.创建表

 create table CourseVideo
(
VideoID int IDENTITY(,) NOT NULL,
CourseID int NOT NULL, VideoName varchar() NULL,
VideoPath [varchar]() NULL,
VideoImage [varchar]() NULL,
VideoDes [varchar]() NULL,
VideoLength int NULL,
primary key(VideoID)
)   

添加数据

INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组1_为什么要使用数组.mp4', N'CourseVideo/1.mp4', N'CourseImage/1.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组2_什么是数组', N'CourseVideo/2.mp4', N'CourseImage/2.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组3_数组的分类及特点', N'CourseVideo/3.mp4', N'CourseImage/3.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组4:一维数组的声明', N'CourseVideo/4.mp4', N'CourseImage/4.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组5:一维数组的初始化', N'CourseVideo/5.mp4', N'CourseImage/5.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组6:一维数组的访问(引用)', N'CourseVideo/6.mp4', N'CourseImage/6.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组7:数组的算法:查找', N'CourseVideo/7.mp4', N'CourseImage/7.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组8:数组的算法:排序 (1)', N'CourseVideo/8.mp4', N'CourseImage/8.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组09:二维数组的声明', N'CourseVideo/9.mp4', N'CourseImage/9', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组10:二维数组的初始化', N'CourseVideo/10.mp4', N'CourseImage/10.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组11:二维数组的访问', N'CourseVideo/11.mp4', N'CourseImage/11.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组12:多维数组简介', N'CourseVideo/12.mp4', N'CourseImage/12.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组13:C语言中的字符串', N'CourseVideo/13.mp4', N'CourseImage/13.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组14:字符数组', N'CourseVideo/14.mp4', N'CourseImage/14.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组15:字符串的输入输出', N'CourseVideo/15.mp4', N'CourseImage/15.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (, , N'数组16:字符串处理函数', N'CourseVideo/16.mp4', N'CourseImage/16.jpg', NULL)
GO

记得视频路径勿加中文,否则视频播放不出来

三.搭建WebService服务器

1.DatableToList.cs文件用于DataTable转换List<T>

 public class DatableToList
{
public static List<T> ConvertToList<T>(DataTable dt) where T : new()
{
//定义集合
List<T> ts = new List<T>(); //获得此模型的类型
Type type = typeof(T); //定义一个临时变量
string tempName = string.Empty; //便利DataTable数据行
foreach (DataRow dr in dt.Rows)
{
T t = new T();
//获得此模型的公共属性
PropertyInfo[] propertys = t.GetType().GetProperties(); //遍历该对象的所有属性
foreach(PropertyInfo pi in propertys)
{
tempName = pi.Name;//将属性名称赋值给临时变量
//检查DataTable是否包含此列(列名==对象的属性名)
if (dt.Columns.Contains(tempName))
{
// 判断此属性是否有Setter
if (!pi.CanWrite) continue;//该属性不可写,直接跳出
//取值
object value = dr[tempName];
//如果非空,则赋给对象的属性
if (value != DBNull.Value)
pi.SetValue(t, value, null);
}
}
//对象添加到泛型集合中
ts.Add(t);
}
return ts;
} }

2.创建Model类库

CourseVideo.cs类

public  class CourseVideo
{
private int videoID; public int VideoID
{
get { return videoID; }
set { videoID = value; }
}
private int courseID; public int CourseID
{
get { return courseID; }
set { courseID = value; }
}
private String videoName; public String VideoName
{
get { return videoName; }
set { videoName = value; }
}
private String videoPath; public String VideoPath
{
get { return videoPath; }
set { videoPath = value; }
}
private String videoImage; public String VideoImage
{
get { return videoImage; }
set { videoImage = value; }
}
    private int videoLength;
      public int VideoLength
{
get { return videoLength; }
set { videoLength = value; }
}
}

3.创建Dal类库

CourseVideoDal.cs类

查询CourseVideo表信息

这是比较简单容易理解的方式,但是字段多的话就很不实用。

//查询视频资源
public List<CourseVideo> Select()
{
List<CourseVideo> list = new List<CourseVideo>();
DataTable dt = new DataTable();
CourseVideo model = null;
DataBase db = new DataBase();
String comstr = "select VideoID,CourseID,VideoName,VideoPath,VideoImage,VideoLength from CourseVideo";
dt = db.GetDataTable(comstr);
for (int i = ; i < dt.Rows.Count;i++ )
{
model = new CourseVideo();
model.VideoID = Convert.ToInt32(dt.Rows[i][]);
model.CourseID = Convert.ToInt32(dt.Rows[i][]);
model.VideoName = dt.Rows[i][].ToString();
model.VideoPath = dt.Rows[i][].ToString();
model.VideoImage = dt.Rows[i][].ToString();
           model.VideoLength = Convert.ToInt32(dt.Rows[i][5]);
          list.Add(model);
       }
        return list;
     }

之前新建的DatableToList.cs类文件就可以用到了,使用泛型将DataTable数据转换为List<T>

泛型之前一直没机会用到,于是自己百度学习了一下,封装好DatableToList文件后,很好的提高代码

了质量,更方便使用。

 //使用泛型 查询视频资源
public List<CourseVideo> Select2()
{
List<CourseVideo> list = new List<CourseVideo>();
DataTable dt = new DataTable();
DataBase db = new DataBase();
String comstr = "select VideoID,CourseID,VideoName,VideoPath,VideoImage,VideoLength from CourseVideo";
dt = db.GetDataTable(comstr);
list = DatableToList.ConvertToList<CourseVideo>(dt);
return list; }

4.新建Web 服务

 只需要在App_Code文件夹下找到Service.cs添加

4.1返回json格式

添加命名空间:

using System.Web.Script.Services;
using System.Web.Script.Serialization;

还有在方法前面声明

[WebMethod(Description = "json查询视频资源")]

 [ScriptMethod(ResponseFormat = ResponseFormat.Json)]

 [WebMethod(Description = "json查询视频资源")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public String VideoSelect()
{
return new JavaScriptSerializer().Serialize(courseVideoDal.Select());
// return dal.Select(); }

4.1返回xml格式

[WebMethod(Description = "xml查询视频资源")]

public List<CourseVideo> xmlVideoSelect()
{
return courseVideoDal.Select();
}

设置外部访问需要在Web.config添加节点:

 <webServices>
<protocols>
<add name="HttpSoap" />
<add name="HttpPost" />
<add name="HttpGet" />
<add name="Documentation" />
</protocols>
</webServices>

看下结果iOS网络开发-打造自己的视频客户端

iOS网络开发-打造自己的视频客户端

接下来把项目部署在IIS服务器上即可使用,如何部署我这就不多说了,可以查一下百度

附件:忘记保存了,这里用到一个工具

WSDL2ObjC-0.6.zip

iOS网络开发-打造自己的视频客户端

Parse WSDL后稍等15秒左右出现Finish!查看导入目录

iOS网络开发-打造自己的视频客户端

将生成的所有文件放置在wsdl2objc文件夹导入项目中

尝试编译出现错误如下:1."libxml/tree.h" file not found

解决办法:

链接libxml2.2dylib库

TARGETS -> Build Phases -> Linking Binary With Libraries-> libxml2.2dylib

TARGETS -> Build Settings -> Search Paths-> Header Search Paths,设置“/usr/include/libxml2”

TARGETS -> Build Phases -> Compile Sources  将Service.m,USAddition.m,NSDate+ISO8601Unparsing.m,NSDate+ISO8601Parsing.m

文件 设置不使用ARC   -fno-objc-arc

手动ARC设置方法如下:

1.在Compiler Flags一列加上-fno-objc-arc就表示禁止这个.m文件的ARC

2.在Compiler Flags一列加上-fobjc-arc就表示开启这个.m文件的ARC

5.创建数据模型

lmjVideo.h文件

//视频ID
@property (assign,nonatomic) int ID; //视频名称
@property (copy,nonatomic) NSString *name; //视频长度
@property (assign,nonatomic) int length; //视频图片
@property (copy,nonatomic) NSString *image; //视频链接
@property (copy,nonatomic) NSString *url; + (instancetype)videoWithDict:(NSDictionary *)dict;

lmjVideo.m文件

+(instancetype)videoWithDict:(NSDictionary *)dict
{
lmjVideo *video = [[self alloc] init];
video.name = dict[@"VideoName"];
video.image = dict[@"VideoImage"];
video.url = dict[@"VideoPath"];
video.length = [dict[@"VideoLength"] intValue];
video.ID = [dict[@"VideoID"] intValue];
return video; // [video setValuesForKeysWithDictionary:dict]; // KVC方法使用前提: 字典中的所有key 都能在 模型属性 中找到 }

自定义cell,对cell内部数据处理的封装

lmjVideoCell.h文件

文件

@class lmjVideo;
@interface lmjVideoCell : UITableViewCell @property (nonatomic,strong) lmjVideo *video;
+ (instancetype)cellWithTableView:(UITableView *)tableView;

lmjVideoCell.m文件

#import "lmjVideoCell.h"
#import "lmjVideo.h"
#import "UIImageView+WebCache.h"
#import "UIView+Extension.h"
@interface lmjVideoCell()
@property (nonatomic,weak) UIView *driver; @end @implementation lmjVideoCell + (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"video";
lmjVideoCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (!cell)
{
cell = [[lmjVideoCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
return cell;
} - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) {
UIView *driver = [[UIView alloc] init];
driver.backgroundColor = [UIColor lightGrayColor];
driver.alpha = 0.2;
[self.contentView addSubview:driver];
self.driver = driver; } return self;
} - (void)setVideo:(lmjVideo *)video
{
_video = video; self.textLabel.text = video.name;
self.detailTextLabel.text = [NSString stringWithFormat:@"时长:%d分钟",video.length]; NSString *imageUrl = [NSString stringWithFormat:@"http://180.84.33.156:8882/%@",video.image];
[self.imageView setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:@"placeholder"]];
} - (void)layoutSubviews
{
[super layoutSubviews]; //调整子控件的frame
CGFloat imageX = ;
CGFloat imageY = ;
CGFloat imageH = self.height - * imageY;
CGFloat imageW = imageH * / ;
self.imageView.frame = CGRectMake(imageX, imageY, imageW, imageH); self.textLabel.x = CGRectGetMaxX(self.imageView.frame) + ; self.detailTextLabel.x = self.textLabel.x; CGFloat driverH = ;
CGFloat driverY = self.height - driverH;
CGFloat driverW = self.width;
self.driver.frame = CGRectMake(, driverY, driverW, driverH); }

分类

UIView+Extension.h文件

添加一个UIView的分类,直接修改UI控件的x值

@property (nonatomic,assign) CGFloat x;
@property (nonatomic,assign) CGFloat y;
@property (nonatomic,assign) CGFloat width;
@property (nonatomic,assign) CGFloat height;

UIView+Extension.m文件

#import "UIView+Extension.h"

@implementation UIView (Extension)

- (void)setX:(CGFloat)x
{
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
} - (CGFloat)x
{
return self.frame.origin.x;
} - (void)setY:(CGFloat)y
{
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
} - (CGFloat)y
{
return self.frame.origin.y;
} - (void)setWidth:(CGFloat)width
{
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame; } - (CGFloat)width
{
return self.frame.size.width;
} - (void)setHeight:(CGFloat)height
{
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}
- (CGFloat)height
{
return self.frame.size.height;
}
@end

实现“视屏列表界面只支持竖屏方向

自定义lmjNavigationController控制器,其继承自UINavigationController

   UIInterfaceOrientationMaskPortrait:竖屏(正常)
UIInterfaceOrientationMaskPortraitUpsideDown:竖屏(上下颠倒)
UIInterfaceOrientationMaskLandscapeLeft:横屏向左
UIInterfaceOrientationMaskLandscapeRight:横屏向右
UIInterfaceOrientationMaskLandscape:横屏(左右都支持)
UIInterfaceOrientationMaskAll:所有都支持

lmjNavigationViewController.m

#import "lmjNavigationViewController.h"

@interface lmjNavigationViewController ()

@end

@implementation lmjNavigationViewController

//控制当前控制器支持那些方向

-(NSUInteger)supportedInterfaceOrientations
{
  //竖屏 
return UIInterfaceOrientationMaskPortrait;
} @end

自定义lmjMoviePlayerViewController控制器,继承MPMoviePlayerViewController

导入MediaPlayer.framework框架,lmjMoviePlayerViewController.h在添加头文件

#import <MediaPlayer/MediaPlayer.h>

iOS网络开发-打造自己的视频客户端

lmjMoviePlayerViewController.m

#import "lmjMoviePlayerViewController.h"

@interface lmjMoviePlayerViewController ()

@end

@implementation lmjMoviePlayerViewController

- (void)viewDidLoad
{
[super viewDidLoad]; // 移除程序进入后台的通知
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
} #pragma mark - 实现这个方法来控制屏幕方向
/**
* 控制当前控制器支持哪些方向
* 返回值是UIInterfaceOrientationMask*
*/
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}

@end

6.主控制器文件代码:

需要注意的是,视频播放的文件路径勿加中文,否则视频不能播放

//
// lmjViewController.m
// 橙子视频客户端
//
// Created by lmj on 15-6-24.
// Copyright (c) 2015年 lmj. All rights reserved.
// #import "lmjViewController.h"
#import "MBProgressHUD+MJ.h"
#import "lmjVideo.h"
#import "UIImageView+WebCache.h"
#import "lmjMoviePlayerViewController.h"
#import "lmjVideoCell.h"
#import "Service.h"
#define strUrl @"http://180.84.33.156:8882"
@interface lmjViewController ()
//所有视频的集合
@property (nonatomic,strong) NSArray *videos;
@end @implementation lmjViewController - (void)viewDidLoad
{
[super viewDidLoad];
[MBProgressHUD showMessage:@"正在加载视频信息..."];
NSString *result;
NSData *data;
ServiceSoap *binding = [Service ServiceSoap];
Service_VideoSelect *request = [[Service_VideoSelect alloc] init];
ServiceSoap12Response *response = [binding VideoSelectUsingParameters:request];
for(id mine in response.bodyParts){
if([mine isKindOfClass:[Service_VideoSelectResponse class]])
{
// [request release];
[MBProgressHUD hideHUD]; result = [mine VideoSelectResult];
data = [result dataUsingEncoding:NSUTF8StringEncoding];
if(data)
{
// NSLog(@"data----%@",data);
NSArray *array =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSMutableArray *videos = [NSMutableArray array];
for (NSDictionary *dict in array) {
lmjVideo *video = [lmjVideo videoWithDict:dict];
[videos addObject:video];
NSLog(@"%@",video.url);
}
self.videos = videos;
[self.tableView reloadData];
}
else{
[MBProgressHUD showError:@"网络繁忙"];
} // NSLog(@"ns----%@",ns);
// NSDictionary *dict= [NSJSONSerialization JSONbjectWithData:data options:NSJSONReadingAllowFragmentS error:nil]; }
} }
#pragma mark -数据源
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.videos.count;
} -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
lmjVideoCell *cell = [lmjVideoCell cellWithTableView:tableView];
cell.video = self.videos[indexPath.row];
return cell;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return ;
} -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
lmjVideo *video = self.videos[indexPath.row]; //播放视频
NSLog(@"%@",video.url);
NSString *videoUrl = [NSString stringWithFormat:@"http://180.84.33.156:8882/%@",video.url];
lmjMoviePlayerViewController *playerVc = [[lmjMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:videoUrl]]; [self presentMoviePlayerViewControllerAnimated:playerVc] ; //全拼播放
} @end