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

一.展示实现

效果

    

 

客户端:                                      服务器端:

          

二.创建表

 1 create table CourseVideo
 2 (
 3     VideoID int IDENTITY(1,1)  NOT NULL,    
 4     CourseID int NOT NULL,   5     VideoName varchar(500)  NULL,  
 6     VideoPath [varchar](100) NULL,
 7     VideoImage [varchar](200) NULL,
 8     VideoDes [varchar](200) NULL,
 9    VideoLength int NULL,
10     primary key(VideoID)
11 )

  

添加数据

INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (1, 1, N'数组1_为什么要使用数组.mp4', N'CourseVideo/1.mp4', N'CourseImage/1.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (2, 1, N'数组2_什么是数组', N'CourseVideo/2.mp4', N'CourseImage/2.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (3, 1, N'数组3_数组的分类及特点', N'CourseVideo/3.mp4', N'CourseImage/3.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (4, 1, N'数组4:一维数组的声明', N'CourseVideo/4.mp4', N'CourseImage/4.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (5, 1, N'数组5:一维数组的初始化', N'CourseVideo/5.mp4', N'CourseImage/5.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (6, 1, N'数组6:一维数组的访问(引用)', N'CourseVideo/6.mp4', N'CourseImage/6.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (7, 1, N'数组7:数组的算法:查找', N'CourseVideo/7.mp4', N'CourseImage/7.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (8, 1, N'数组8:数组的算法:排序 (1)', N'CourseVideo/8.mp4', N'CourseImage/8.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (9, 1, N'数组09:二维数组的声明', N'CourseVideo/9.mp4', N'CourseImage/9', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (10, 1, N'数组10:二维数组的初始化', N'CourseVideo/10.mp4', N'CourseImage/10.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (11, 1, N'数组11:二维数组的访问', N'CourseVideo/11.mp4', N'CourseImage/11.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (12, 1, N'数组12:多维数组简介', N'CourseVideo/12.mp4', N'CourseImage/12.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (13, 1, N'数组13:C语言中的字符串', N'CourseVideo/13.mp4', N'CourseImage/13.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (14, 1, N'数组14:字符数组', N'CourseVideo/14.mp4', N'CourseImage/14.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (15, 1, N'数组15:字符串的输入输出', N'CourseVideo/15.mp4', N'CourseImage/15.png', NULL)
GO
INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (16, 1, 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 = 0; i < dt.Rows.Count;i++ )
            {
                model = new CourseVideo();
                model.VideoID = Convert.ToInt32(dt.Rows[i][0]);
                model.CourseID = Convert.ToInt32(dt.Rows[i][1]);
                model.VideoName = dt.Rows[i][2].ToString();
                model.VideoPath = dt.Rows[i][3].ToString();
                model.VideoImage = dt.Rows[i][4].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>

看下结果

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

 

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

WSDL2ObjC-0.6.zip

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

将生成的所有文件放置在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 = 10;
    CGFloat imageY = 10;
    CGFloat imageH = self.height - 2 * imageY;
    CGFloat imageW = imageH * 200 / 112;
    self.imageView.frame = CGRectMake(imageX, imageY, imageW, imageH);
    
    self.textLabel.x = CGRectGetMaxX(self.imageView.frame) + 10;
    
    self.detailTextLabel.x = self.textLabel.x;
    
    CGFloat driverH = 1;
    CGFloat driverY = self.height - driverH;
    CGFloat driverW = self.width;
    self.driver.frame = CGRectMake(0, 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>

 

 

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 70;
}

-(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

 

posted @ 2015-06-29 15:01  Linxxx~  阅读(1934)  评论(3编辑  收藏  举报