зеркало из https://github.com/xamarin/ios-samples.git
Add new sample - CustomInputStream
This commit is contained in:
Родитель
3b1709b284
Коммит
af478bf807
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
using MonoTouch.Foundation;
|
||||
using MonoTouch.UIKit;
|
||||
|
||||
using MonoTouch.Dialog;
|
||||
|
||||
namespace InputStreamTest
|
||||
{
|
||||
[Register ("AppDelegate")]
|
||||
public partial class AppDelegate : UIApplicationDelegate
|
||||
{
|
||||
UIWindow window;
|
||||
DialogViewController dvc;
|
||||
NativeUploader uploader;
|
||||
StyledStringElement status;
|
||||
StyledStringElement upload;
|
||||
|
||||
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
|
||||
{
|
||||
window = new UIWindow (UIScreen.MainScreen.Bounds);
|
||||
|
||||
dvc = new DialogViewController (new RootElement ("InputStreamTest")
|
||||
{
|
||||
new Section () {
|
||||
(upload = new StyledStringElement ("Upload", Upload)),
|
||||
(status = new StyledStringElement ("")),
|
||||
}
|
||||
});
|
||||
|
||||
upload.Alignment = UITextAlignment.Center;
|
||||
status.Alignment = UITextAlignment.Center;
|
||||
|
||||
window.RootViewController = dvc;
|
||||
window.MakeKeyAndVisible ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Upload ()
|
||||
{
|
||||
TcpListener listener = new TcpListener (new IPEndPoint (IPAddress.Loopback, 0));
|
||||
listener.Start ();
|
||||
|
||||
Console.WriteLine ("Listening on: {0}", listener.LocalEndpoint);
|
||||
|
||||
uploader = new NativeUploader ();
|
||||
uploader.UploadStream ("http://127.0.0.1:" + ((IPEndPoint) listener.LocalEndpoint).Port.ToString (), 1000, () =>
|
||||
{
|
||||
Console.WriteLine ("Upload completed.");
|
||||
});
|
||||
|
||||
listener.BeginAcceptSocket ((IAsyncResult res) =>
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem ((v) =>
|
||||
{
|
||||
using (var socket = listener.EndAcceptSocket (res)) {
|
||||
byte [] buffer = new byte[1024];
|
||||
int read;
|
||||
|
||||
// receive headers
|
||||
read = socket.Receive (buffer);
|
||||
BeginInvokeOnMainThread (() => { status.Caption = "Received headers..."; dvc.ReloadData (); });
|
||||
Console.WriteLine ("\n" + System.Text.ASCIIEncoding.ASCII.GetString (buffer, 0, read));
|
||||
|
||||
// send 100 Continue
|
||||
socket.Send (System.Text.ASCIIEncoding.ASCII.GetBytes (@"HTTP/1.1 100 Continue\r\n\r\n"));
|
||||
|
||||
// receive data
|
||||
read = socket.Receive (buffer);
|
||||
BeginInvokeOnMainThread (() => { status.Caption = "Received data"; dvc.ReloadData (); });
|
||||
Console.WriteLine ("\n" + System.Text.ASCIIEncoding.ASCII.GetString (buffer, 0, read));
|
||||
|
||||
// send 200 OK
|
||||
socket.Send (System.Text.ASCIIEncoding.ASCII.GetBytes (@"HTTP/1.1 200 OK\r\n\r\n"));
|
||||
}
|
||||
|
||||
listener.Stop ();
|
||||
});
|
||||
}, null);
|
||||
}
|
||||
|
||||
static void Main (string[] args)
|
||||
{
|
||||
UIApplication.Main (args, null, "AppDelegate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
|
||||
<ProductVersion>10.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}</ProjectGuid>
|
||||
<ProjectTypeGuids>{6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>InputStreamTest</RootNamespace>
|
||||
<AssemblyName>InputStreamTest</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<MtouchDebug>true</MtouchDebug>
|
||||
<MtouchProfiling>true</MtouchProfiling>
|
||||
<MtouchLink>None</MtouchLink>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Commandlineparameters>foobar</Commandlineparameters>
|
||||
<CrashReportingApiKey />
|
||||
<MtouchUseSGen>true</MtouchUseSGen>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<MtouchLink>None</MtouchLink>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\iPhone\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<CodesignKey>iPhone Developer</CodesignKey>
|
||||
<MtouchDebug>true</MtouchDebug>
|
||||
<MtouchProfiling>true</MtouchProfiling>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<MtouchExtraArgs>--keeptemp -v -v -v</MtouchExtraArgs>
|
||||
<MtouchI18n />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\iPhone\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<CodesignKey>iPhone Developer</CodesignKey>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<MtouchI18n />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="monotouch" />
|
||||
<Reference Include="MonoTouch.Dialog-1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Info.plist" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AppDelegate.cs" />
|
||||
<Compile Include="NativeUploader.cs" />
|
||||
<Compile Include="ZInputStream.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InputStreamTest", "InputStreamTest.csproj", "{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||
Debug|iPhone = Debug|iPhone
|
||||
Release|iPhone = Release|iPhone
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
StartupItem = InputStreamTest.csproj
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,145 @@
|
|||
using System;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using MonoTouch.Foundation;
|
||||
|
||||
namespace InputStreamTest
|
||||
{
|
||||
public class NativeUploader : NSObject
|
||||
{
|
||||
NSMutableUrlRequest request;
|
||||
NSUrlConnection url_connection;
|
||||
ZInputStream random_input_stream;
|
||||
Dictionary<string,string> headers;
|
||||
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (url_connection != null) {
|
||||
url_connection.Dispose ();
|
||||
url_connection = null;
|
||||
}
|
||||
|
||||
if (request != null) {
|
||||
request.BodyStream = null;
|
||||
request.Dispose ();
|
||||
request = null;
|
||||
}
|
||||
|
||||
if (random_input_stream != null) {
|
||||
random_input_stream.Dispose ();
|
||||
random_input_stream = null;
|
||||
}
|
||||
|
||||
base.Dispose (disposing);
|
||||
}
|
||||
|
||||
public void AddHeader (string key, string value)
|
||||
{
|
||||
if (headers == null)
|
||||
headers = new Dictionary<string, string> ();
|
||||
|
||||
headers.Add (key, value);
|
||||
}
|
||||
|
||||
public void UploadStream (string url, long content_length, Action completed)
|
||||
{
|
||||
if (url == null)
|
||||
throw new ArgumentNullException ("url");
|
||||
|
||||
AddHeader ("Expect", "100-continue");
|
||||
AddHeader ("Content-Type", "application/octet-stream");
|
||||
AddHeader ("Content-Length", content_length.ToString ());
|
||||
|
||||
InvokeOnMainThread (delegate {
|
||||
try {
|
||||
request = CreateNativePostRequest (url, content_length);
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine ("Exception uploading stream");
|
||||
Console.WriteLine (e);
|
||||
completed ();
|
||||
return;
|
||||
}
|
||||
|
||||
url_connection = NSUrlConnection.FromRequest (request, new NativeUrlDelegate ((body) => {
|
||||
completed ();
|
||||
request.Dispose ();
|
||||
}, (reason) => {
|
||||
Console.WriteLine ("upload failed: " + reason);
|
||||
completed ();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
NSMutableUrlRequest CreateNativePostRequest (string url, long content_length)
|
||||
{
|
||||
NSUrl nsurl = NSUrl.FromString (url);
|
||||
|
||||
if (nsurl == null)
|
||||
throw new Exception ("Invalid upload URL, could not create NSUrl from: '" + url + "'.");
|
||||
|
||||
NSMutableUrlRequest request = new NSMutableUrlRequest (nsurl);
|
||||
|
||||
request.HttpMethod = "POST";
|
||||
|
||||
random_input_stream = new ZInputStream (content_length);
|
||||
|
||||
request.BodyStream = random_input_stream;
|
||||
|
||||
if (headers != null) {
|
||||
foreach (var header in headers)
|
||||
request [header.Key] = header.Value;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private class NativeUrlDelegate : NSUrlConnectionDelegate {
|
||||
Action<string> success_callback;
|
||||
Action<string> failure_callback;
|
||||
NSMutableData data;
|
||||
int status_code;
|
||||
|
||||
public NativeUrlDelegate (Action<string> success, Action<string> failure)
|
||||
{
|
||||
success_callback = success;
|
||||
failure_callback = failure;
|
||||
data = new NSMutableData();
|
||||
}
|
||||
|
||||
public override void ReceivedData (NSUrlConnection connection, NSData d)
|
||||
{
|
||||
data.AppendData (d);
|
||||
}
|
||||
|
||||
public override void ReceivedResponse (NSUrlConnection connection, NSUrlResponse response)
|
||||
{
|
||||
var http_response = response as NSHttpUrlResponse;
|
||||
if (http_response == null) {
|
||||
Console.WriteLine ("Received non HTTP url response: '{0}'", response);
|
||||
status_code = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
status_code = http_response.StatusCode;
|
||||
Console.WriteLine ("Status code of result: '{0}'", status_code);
|
||||
}
|
||||
|
||||
public override void FailedWithError (NSUrlConnection connection, NSError error)
|
||||
{
|
||||
if (failure_callback != null)
|
||||
failure_callback (error.LocalizedDescription);
|
||||
}
|
||||
|
||||
public override void FinishedLoading (NSUrlConnection connection)
|
||||
{
|
||||
if (status_code != 200) {
|
||||
failure_callback (string.Format ("Did not receive a 200 HTTP status code, received '{0}'", status_code));
|
||||
return;
|
||||
}
|
||||
|
||||
success_callback (data.ToString ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
CustomInputStream
|
||||
=================
|
||||
|
||||
This sample illustrates how to derive from NSInputStream and create subclass that is toll-free
|
||||
bridged to CFReadStream that can be used with NSMutableUrlRequest.
|
||||
|
||||
Note that the API required to implement a subclass of NSInputStream that is toll-free bridged to
|
||||
CFReadStream is considered private API by Apple, and may thus cause an app to be rejected
|
||||
from the AppStore.
|
||||
|
||||
This sample requires at least MonoTouch 5.3.4.
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
Rolf Bjarne Kvinge
|
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using MonoTouch.CoreFoundation;
|
||||
using MonoTouch.Foundation;
|
||||
|
||||
namespace InputStreamTest
|
||||
{
|
||||
[Preserve (AllMembers = true)]
|
||||
public class ZInputStream : NSInputStream
|
||||
{
|
||||
NSStreamStatus status;
|
||||
long read_length;
|
||||
long total_length;
|
||||
|
||||
public ZInputStream (long total_length) : base ()
|
||||
{
|
||||
status = NSStreamStatus.NotOpen;
|
||||
this.total_length = total_length;
|
||||
}
|
||||
|
||||
public override NSStreamStatus Status {
|
||||
get {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Open ()
|
||||
{
|
||||
status = NSStreamStatus.Open;
|
||||
Notify (CFStreamEventType.OpenCompleted);
|
||||
}
|
||||
|
||||
public override void Close ()
|
||||
{
|
||||
status = NSStreamStatus.Closed;
|
||||
}
|
||||
|
||||
public override bool HasBytesAvailable ()
|
||||
{
|
||||
return total_length > read_length;
|
||||
}
|
||||
|
||||
public override int Read (IntPtr buffer, uint len)
|
||||
{
|
||||
int actual = Math.Min ((int) len, (int) (total_length - read_length));
|
||||
|
||||
byte [] bytes = new byte [actual];
|
||||
for (int i = 0; i < actual; i++)
|
||||
bytes [i] = (byte) 'z';
|
||||
|
||||
read_length += actual;
|
||||
|
||||
Marshal.Copy (bytes, 0, buffer, actual);
|
||||
|
||||
if (actual == 0)
|
||||
Notify (CFStreamEventType.EndEncountered);
|
||||
|
||||
return actual;
|
||||
}
|
||||
|
||||
protected unsafe override bool GetBuffer (out IntPtr buffer, out uint len)
|
||||
{
|
||||
// Just call the base implemention (which will return false)
|
||||
return base.GetBuffer (out buffer, out len);
|
||||
}
|
||||
|
||||
protected override bool SetCFClientFlags (CFStreamEventType inFlags, IntPtr inCallback, IntPtr inContextPtr)
|
||||
{
|
||||
// Just call the base implementation, which knows how to handle everything.
|
||||
return base.SetCFClientFlags (inFlags, inCallback, inContextPtr);
|
||||
}
|
||||
|
||||
public override void ScheduleInCFRunLoop (IntPtr runloop, string mode)
|
||||
{
|
||||
Notify (CFStreamEventType.HasBytesAvailable);
|
||||
}
|
||||
|
||||
public override void UnscheduleInCFRunLoop (IntPtr runloop, string mode)
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче