Xamarin+SignalR开发Android应用

原创 2016年06月29日 15:22:28

Xamarin可以使用C#语言开发原生的Android和iOS应用,被微软收购后更是热度不减;而SignalR是微软推出的实时通信技术。之前在项目中用过SignalR,而Xamarin则是首次接触,本次是想结合二者开发一个Windows、Android、iOS平台间实时通信的示例。

开发环境 说明
操作系统 Windows 10 professional
编译器 VS 2015 update2
插件 Xamarin for VisualStudio
其他 Android SDK,Android Emulater

本实例参考了以下文章:

[ How To Use SignalR in iOS and Android Apps ]
[ Running SignalR on Mono]
[ Using SignalR in native Android and iOS apps]
[ Xamarin.Android快速入门]
[Using SignalR in WinForms and WPF]

感谢以上文章的作者!


1.创建服务端

由于之前写过WPF的服务端,所以直接拿来用了。

1.1新建项目ServerApp

选择Windows>WPF应用程序,添加新项目ServerApp。这里框架依然沿用以前的.NET Framework 4.5,并未使用最新的4.6.1 。
这里写图片描述

1.2引用SignalR包

选择“工具>NuGet包管理器>管理解决方案的NuGet程序包”

搜索“SignalR”,相应的包全部安装上(有些包服务端用不上,但是客户端后面会用上)。安装成功后会在项目引用中看到SignalR的几个引用已经添加进来了。
这里写图片描述

1.3添加启动入口和Hub

添加Startup.cs作为程序启动的入口。

using Owin;//必需的程序集引用

namespace ServerApp
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

添加MyHub.cs作为主要服务处理程序。MyHub继承于Hub并实现其接口,IMyHub是自己写的接口,目前只有一个方法“Task SendPlatform(string platform,string message)”。方法SendPlatform就是后面要用到的通信方法。

using Microsoft.AspNet.SignalR;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
using System.Windows;
using Model;

namespace ServerApp
{
    public class MyHub:Hub,IMyHub
    {
        public override Task OnConnected()
        {
            return base.OnConnected();
        }
        public override Task OnDisconnected(bool stopCalled)
        {
            return base.OnDisconnected(stopCalled);
        }
        public override Task OnReconnected()
        {
            return base.OnReconnected();
        }

        public Task SendPlatform(string platform,string message)
        {
            return Clients.All.sendplatform(platform, message);
        }
    }
}

1.4添加启动服务方法

在主页面的后台MainWindow.cs添加控制服务启动及停止的方法。

namespace ServerApp
{
    public partial class MainWindow : Window
    {
        #region 通信设置
        public IDisposable SignalR { get; set; }
        static string ServerURI = ConfigurationManager.AppSettings["ServiceUri"]; //全局通信链接,地址为服务端所在主机IP地址,端口号可任意指定
        #endregion
        public MainWindow()
        {
            InitializeComponent();
            StartServer();
        }
        private void StartServer()
        {
            try
            {
                SignalR = WebApp.Start(ServerURI);
            }
            catch (TargetInvocationException)
            {
                WriteToConsole("已存在运行的服务:" + ServerURI);
                this.Dispatcher.Invoke(() => btn_Start.IsEnabled = true);
                return;
            }
            this.Dispatcher.Invoke(() => btn_Stop.IsEnabled = true);
            WriteToConsole("服务正在运行:" + ServerURI);
        }
    }
}

服务URI在配置文件app.config中设置。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <!--通信连接地址-->
    <add key="ServiceUri" value="http://127.0.0.1:46900/" />
  </appSettings>
</configuration>

2创建共享项目ShareMe

选择“Windows>共享项目”,添加项目ShareMe,用于公共方法共享,Android、iOS、Windows客户端都用的到。
这里写图片描述
添加类文件OSClient.cs

using System;
using Microsoft.AspNet.SignalR.Client;
using System.Threading.Tasks;

namespace ShareMe
{
    public class OSClient
    {
        private readonly string _platform;
        private readonly HubConnection _connection;
        private readonly IHubProxy _proxy;

        public event EventHandler<string> OnSendPlatform;

        public OSClient(string platform)
        {
            _platform = platform;
            _connection = new HubConnection("http://127.0.0.1:46900");//url要与服务端的ServerUri保持一致,否则通信不上
            _proxy = _connection.CreateHubProxy("MyHub");//创建Hub,与服务端MyHub类名一致
        }
        public async Task Connect()
        {
            await _connection.Start();
            _proxy.On("sendplatform",(string platform,string message)=> {
                if (OnSendPlatform!=null)
                {
                    OnSendPlatform(this, string.Format("{0}:{1}",platform,message));
                }
            });
            Send("Connected");
        }
        public Task Send(string message)
        {
            return _proxy.Invoke("SendPlatform", _platform, message;//调用方法名与服务端方法名一致
        }
    }
}

3创建安卓客户端AndroidApp

3.1新建项目

选择“Android>Blank App”新建项目AndroidApp。
这里写图片描述

3.2添加相关引用

首先添加共享项目ShareMe的引用
这里写图片描述
然后添加SignalR程序包的引用。在添加SignalR程序包的过程中遇到了比较棘手的问题,使用NuGet为项目添加SignalR引用时总是报错。
这里写图片描述
考虑是由于Mono还不支持的当前SignalR的版本,在网上查阅了相关资料后发现,SignalR是可以用于Mono的,但是需要使用portbale版本,可以在解决方案根目录下“packages\Microsoft.AspNet.SignalR.Client.2.2.0\lib\portable-net45+sl5+netcore45+wp8+wp81”找到,手动添加引用。
这里写图片描述
添加引用后编译会出错,把错误提示中出现的未引用程序包通过NuGet添加下(有Newton.Json及System.Net.Http等)。其中可能会有System.Net.Http.Extensions也需要手动添加引用。所有引用添加完后再次编译提示

这当中还有一个小插曲,就是引用添加完之后,编译总是失败并提示:

“aapt.exe”已退出,代码为“-1073741819”

尝试了N多次,即使新建项目后什么都不做依然会报错,这就比较奇怪了。后来发现了一篇Xamarin作者之一的文章,说到是由于Android SDK Bulid-tools 22.0.1自身问题所致,移除这个版本的编译工具即可。但是我在Android SDK Manager中没有安装这个版本,所以更加疑惑,后来向别人请教说可能是Android SDK Bulid-tools 24有问题。于是把这个版本的也卸载了,问题解决。
这里写图片描述

3.3添加客户端方法

添加完成后的项目文件结构如下:
这里写图片描述
Resources是项目资源所在,其中drawable主要是图片,layout是布局,values是静态资源,这些文件夹都是项目创建时自动生成的。后台处理主要包含在MainActivity.cs中。
打开布局文件“Resources\layout\Main.xml”,在设计器中添加一个EditText和ListView(把原来的删掉,直接从工具箱里拖,然后再属性中修改id)
这里写图片描述
这里写图片描述
添加完成后重新生成一下,不然资源文件在后台找不到。修改完成后的布局文件Main.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/Input" />
    <ListView
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/Messages" />
</LinearLayout>

在后台文件MainActivity.cs中添加相应的方法:

using Android.App;
using Android.Widget;
using Android.OS;
using ShareMe;//共享项目引用
using Android.Views.InputMethods;
using System.Collections.Generic;

namespace AndroidApp
{
    [Activity(Label = "AndroidApp", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        int count = 1;

        protected override async void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            var client = new OSClient("Android");

            var input = FindViewById<EditText>(Resource.Id.Input);
            var messages = FindViewById<ListView>(Resource.Id.Messages);
            var inputManager = (InputMethodManager)GetSystemService(InputMethodService);
            var adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, new List<string>());
            messages.Adapter = adapter;

            await client.Connect();
            input.EditorAction += delegate
            {
                inputManager.HideSoftInputFromWindow(input.WindowToken, HideSoftInputFlags.None);
                if (string.IsNullOrEmpty(input.Text))
                {
                    return;
                }
                client.Send(input.Text);
                input.Text = "";
            };
            client.OnSendPlatform+= (sender, message) => RunOnUiThread(() =>adapter.Add(message));
        }
    }
}

最后启动服务端,在模拟器上运行AndroidApp查看效果。


后记

写这个示例中间不少曲折,但也收获很多。写的过程中查找好多的文章都是几年前的,时效性可能有折扣,还是要多想多看多学多用。

版权声明:本文为博主原创文章,未经博主允许不得转载。

SignalR推送服务在Android的实现 SignalA

SignalA是老外写的用于实现.net服务器至安卓端的实现,支持版本为android 2.3或以上,由于我的版本最低是2.2,所以只有把源码下下来自己改,如果你觉得太多了可自己编译成jar引用,本来...
  • panderman
  • panderman
  • 2013年10月26日 18:33
  • 15798

SignalR推送消息到android客户端

结合官方demo http://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr ...
  • zjclugger
  • zjclugger
  • 2016年08月03日 16:03
  • 3414

android(SignalA)接收.net(SignalR)推送过来的消息

从网络上搜索到的Demo,自己进行了稍微的改动 Signala类库从https://github.com/erizet/SignalA获得,不过相关引用有错误,需要手动修正。 package com....
  • zjclugger
  • zjclugger
  • 2016年08月03日 16:13
  • 3593

android使用signalR

  • 2016年11月30日 17:04
  • 845KB
  • 下载

android 用signalr 实现推送服务

我做的app需要实现signalr 推送服务  有两种方法 一种人家已经给我们集成了还有视频教程 地址为 https://www.youtube.com/watch?v=f9ih_M7PC10 ...
  • chenaini119
  • chenaini119
  • 2015年03月06日 09:59
  • 2181

Xamarin android中使用signalr实现即时通讯

xamarin android中使用signalr实现不同平台间的即时通讯
  • kebi007
  • kebi007
  • 2016年12月09日 23:59
  • 3829

SignalR+HTML5实现消息推送及Android通知栏消息

最近在研究使用SignalR实现跨平台的消息中心,WebAPI+SignalR作为数据接口和消息中心,客户端包含WPF桌面应用、Web应用和Android移动应用。这其中关键的功能点在于接收到实时消息...
  • lordwish
  • lordwish
  • 2017年07月15日 16:37
  • 2403

Android端SignalR.jar包

  • 2016年11月05日 09:48
  • 146KB
  • 下载

Android手动显示和隐藏软键盘方法总结

本文介绍Android中如何通过代码来显示和隐藏软键盘
  • ccpat
  • ccpat
  • 2015年07月02日 00:14
  • 26618

android 软键盘 InputMethodManager

1、需要强制隐藏或显示Android输入法键盘时,下边这个是让输入法状态发生逆转,如果当前未显示则显示出来,如果显示出来则隐藏。                //设置键盘输入状态          ...
  • u010127332
  • u010127332
  • 2015年10月17日 11:02
  • 516
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Xamarin+SignalR开发Android应用
举报原因:
原因补充:

(最多只允许输入30个字)