C#的Xamarin开发小米盒子应用并以WCF实现微信通知

对于熟悉C#语言的开发人员而言,用Xamarin开发Android应用也是一个不错的选择。小米盒子是Android系统。当然也就能够使用Xamarin来开发。首选来看效果图。

注:(1).左图是从数据库中拉取用户列表(图中的用户的虚拟的)

(2)中间图是依据选中的用户发起微信通知

(3)右图是微信企业号中收到的通知

一、在VS中建立Android应用

1.布局主界面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/btnLoadUser"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/LoadUser" />
        <Button
            android:id="@+id/btnWeiXinNotify"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/WeiXinNotify" />
        <Button
            android:id="@+id/btnClear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/Clear" />
    </LinearLayout>
    <ListView
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/listView1" />
</LinearLayout>

注:因为小米盒子使用的遥控器控制,不像手机是触摸屏的。所以界面中尽量以button、简易图表的形式展现。以方便控制。

2.主界面MainActivity的CS代码

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text;

namespace XiaoMiBoxDemo
{
    [Activity(Label = "小米盒子应用演示样例", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        private Button _btnLoadUser = null;
        private Button _btnWeiXinNotify = null;
        private Button _btnClear = null;
        private ListView _listView = null;
        private List<UserInfo> _userList = null;

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

            SetContentView(Resource.Layout.Main);
            FetchControls();
            BindEvents();
        }

        private void BindEvents()
        {
            _btnLoadUser.Click += _btnLoadUser_Click;
            _listView.ItemClick += _listView_ItemClick;
            _btnWeiXinNotify.Click += _btnWeiXinNotify_Click;
            _btnClear.Click += _btnClear_Click;
        }

        void _btnClear_Click(object sender, EventArgs e)
        {
            _listView.Adapter = null;
            _userList.Clear();
        }

        void _btnWeiXinNotify_Click(object sender, EventArgs e)
        {
            if (_userList == null || _userList.Count <= 0)
            {
                Toast.MakeText(this, "请选择要通知的用户", ToastLength.Long).Show();
                return;
            }

            String qyNoIds = "";
            bool hasSelectedUser = false;
            foreach (UserInfo _userInfo in _userList)
            {
                if (!_userInfo.IsSelected)
                {
                    continue;
                }
                hasSelectedUser = true;
                if (String.IsNullOrWhiteSpace(_userInfo.QYNo))
                {
                    continue;
                }

                if (String.IsNullOrWhiteSpace(qyNoIds))
                {
                    qyNoIds = _userInfo.QYNo;
                }
                else
                {
                    qyNoIds += "|" + _userInfo.QYNo;
                }
            }

            if (String.IsNullOrWhiteSpace(qyNoIds))
            {
                if (hasSelectedUser)
                {
                    Toast.MakeText(this, "所选择的用户没有绑定企业号", ToastLength.Long).Show();
                }
                else
                {
                    Toast.MakeText(this, "请选择要通知的用户", ToastLength.Long).Show();
                }
                return;
            }
            String returnErrorMsg = "";
            EditText editText = new EditText(this);
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.SetTitle("通知信息");
            builder.SetView(editText);
            EventHandler<DialogClickEventArgs> okClick = delegate
            {
                String message = editText.Text;
                if (WeiXinHelper.SendContent(out returnErrorMsg, qyNoIds, message))
                {
                    returnErrorMsg = "发送成功";
                }
                Toast.MakeText(this, returnErrorMsg, ToastLength.Long).Show();
            };
            builder.SetNegativeButton("取消", delegate { });
            builder.SetPositiveButton("确定", okClick);

            builder.Show();
        }

        void _listView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
        {
            UserInfo userInfo = _userList[e.Position];
            userInfo.IsSelected = (!userInfo.IsSelected);
            String guid = String.Format("{0}", e.View.Tag);
            if (guid.Equals(userInfo.Guid))
            {
                e.View.FindViewById<CheckBox>(Resource.Id.checkBoxUser).Checked = userInfo.IsSelected;
            }
        }

        private void FetchControls()
        {
            _btnLoadUser = FindViewById<Button>(Resource.Id.btnLoadUser);
            _btnWeiXinNotify = FindViewById<Button>(Resource.Id.btnWeiXinNotify);
            _btnClear = FindViewById<Button>(Resource.Id.btnClear);
            _listView = FindViewById<ListView>(Resource.Id.listView1);
        }

        void _btnLoadUser_Click(object sender, EventArgs e)
        {
            try
            {
                String sql = " SELECT * FROM TUser ";
                DataTable dt = DBUtil.Query(sql).Tables[0];
                String account = "";
                String nickname = "";
                String qyNo = "";
                String guid = "";
                _userList = new List<UserInfo>();
                foreach (DataRow row in dt.Rows)
                {
                    guid = String.Format("{0}", row["u_guid"]);
                    account = String.Format("{0}", row["u_account"]);
                    nickname = String.Format("{0}", row["u_nickname"]);
                    qyNo = String.Format("{0}", row["u_qyNo"]);
                    _userList.Add(new UserInfo()
                    {
                        Guid = guid,
                        Account = account,
                        Nickname = nickname,
                        QYNo = qyNo,
                        IsSelected = false
                    });
                }
                _listView.Adapter = new UserListAdapter(this, _userList);
            }
            catch (Exception ex)
            {
                Toast.MakeText(this, ex.Message, ToastLength.Long).Show();
            }
        }
    }
}

注:(1)使用自己定义的DBUtil类来查询数据库。

(2)_listView使用自己定义的UserListAdapter来绑定数据。

(3)给对应的button和_listView的项加入点击事件

(3)须要特别注意的是MainActivity定义的上一行有 [Activity(Label = "小米盒子应用演示样例", MainLauncher = true, Icon = "@drawable/icon")]的代码,这里的Label将会影响到终于应用显示的名称(包含应用列表和应用启动后的),而icon在更换了之后。除了在项目属性中调整之外,这里也要一并调整,否则会编译只是。

3.数据库工具类DBUtil

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace XiaoMiBoxDemo
{
    public class DBUtil
    {
        private static String ConnectionString = "server=数据库server;database=DBDemo;uid=sa;pwd=abc;pooling=false;Connect Timeout=120;";

        /// <summary>
        /// 运行查询语句。返回DataSet
        /// </summary>
        /// <param name="SQLString">查询语句</param>
        /// <returns>DataSet</returns>
        public static DataSet Query(string SQLString)
        {
            using (SqlConnection connection = new SqlConnection(ConnectionString))
            {
                DataSet ds = new DataSet();
                try
                {
                    connection.Open();
                    SqlDataAdapter command = new SqlDataAdapter(SQLString, connection);
                    command.Fill(ds, "ds");
                }
                catch (System.Data.SqlClient.SqlException ex)
                {
                    throw new Exception(ex.Message);
                }
                return ds;
            }
        }
    }
}

注:(1).数据库server。须要换成对应的值。比方192.168.1.101或www.xxx.com:8090等

(2).C#下的Android连接数据库时,直接使用.Net的数据库连接方式。不必像eclipse下那么麻烦。只是须要注意,记得要引用对应的DLL(System.Data).该DLL一定要引用Android下的,而不.Net下的。这是我的Android的System.Data.dll路径C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Data.dll。

(3).记得设置Android应用的编码。否则在运行SQL时可能会出现"Code page 936 not support"。这是由于我们开发的应用的字符集和数据库server的字符集不一致造成的。

从图上能够看到SQLserver使用的Chinese_PRC_CI_AS的排序规则。这是GBK的字符集,所以我们的应用也需需有这种字符集支持,为此须要给应用加一个配置,见下图。项目->右键->属性,然后按下图配置。

注:CJK表示的中日韩的字符集。

4.列表适配器UserListAdapter

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Views;
using Android.Widget;

namespace XiaoMiBoxDemo
{
    public class UserListAdapter : BaseAdapter<UserInfo>
    {
        /// <summary>
        /// 全部UserInof 的数据
        /// </summary>
        List<UserInfo> items;

        Activity context;

        public UserListAdapter(Activity context, List<UserInfo> items)
            : base()
        {
            this.context = context;
            this.items = items;
        }

        public override long GetItemId(int position)
        {
            return position;
        }
        public override UserInfo this[int position]
        {
            get { return items[position]; }
        }
        public override int Count
        {
            get { return items.Count; }
        }

        /// <summary>
        /// 系统会呼叫 而且render.
        /// </summary>
        /// <param name="position"></param>
        /// <param name="convertView"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            var item = items[position];
            var view = convertView;
            if (view == null)
            {
                //使用自订的UserListItemLayout
                view = context.LayoutInflater.Inflate(Resource.Layout.UserListItemLayout, null);
            }

            view.FindViewById<TextView>(Resource.Id.textViewAccount).Text = item.Account;
            view.FindViewById<TextView>(Resource.Id.textViewNickname).Text = item.Nickname;
            view.FindViewById<TextView>(Resource.Id.textViewQYNo).Text = item.QYNo;
            view.FindViewById<CheckBox>(Resource.Id.checkBoxUser).Checked = item.IsSelected;
            view.Tag = item.Guid;
            return view;
        }
    }
}

当中UserInfo的代码例如以下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace XiaoMiBoxDemo
{
    public class UserInfo
    {
        /// <summary>
        /// Guid
        /// </summary>
        public String Guid { get; set; }

        /// <summary>
        /// 帐号
        /// </summary>
        public String Account { get; set; }

        /// <summary>
        /// 昵称
        /// </summary>
        public String Nickname { get; set; }

        /// <summary>
        /// 企业号
        /// </summary>
        public String QYNo { get; set; }

        /// <summary>
        /// 是否选中
        /// </summary>
        [DefaultValue(false)]
        public bool IsSelected { get; set; }
    }
}

以下是每个Item的布局代码

<?

xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="10px">
    <CheckBox
        android:text=""
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="false"
        android:id="@+id/checkBoxUser" />
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">
            <TextView
                android:text="@string/Account"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <TextView
                android:text="Text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/textViewAccount" />
        </LinearLayout>
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">
            <TextView
                android:text="@string/Nickname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <TextView
                android:text="Text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/textViewNickname" />
        </LinearLayout>
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">
            <TextView
                android:text="@string/QYNo"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <TextView
                android:text="Text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/textViewQYNo" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

5.字符串变量Strings.xml

<?

xml version="1.0" encoding="utf-8"?

>
<resources>
  <string name="LoadUser">用户列表</string>
  <string name="WeiXinNotify">微信通知</string>
  <string name="Clear">清空列表</string>
  <string name="ApplicationName">小米盒子应用演示样例</string>
  <string name="Account">帐号:</string>
  <string name="Nickname">昵称:</string>
  <string name="QYNo">企业号:</string>
</resources>

二.WCF实现微信通知

1.原理:在实现了微信企业号的WCF服务后。在Android端以Web服务调用的形式来发起通知。

2.引用WCF

在WinForm或者Asp.Net下调用WCF。仅仅须要直接加入服务引用就能够了。在Xamarin下也是假设,所不同的是,这里加入的是Web引用。见下图。

这时在我们的项目中,会多一个Web References的目录。以下会有一个WeiXinService,见下图。

3.调用WCF

为了方便以后调用,这里将调用封装到WeiXinHelper类中,代码例如以下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XiaoMiBoxDemo
{
    #region WeiXinMessageType
    /// <summary>
    /// 微信的消息类型
    /// </summary>
    public sealed class WeiXinMessageType
    {
        public const string TEXT = "text";
    }
    #endregion

    #region WeiXinMessageEncription
    /// <summary>
    /// 微信的消息加密开关
    /// </summary>
    public sealed class WeiXinMessageEncription
    {
        /// <summary>
        /// 不须要加密
        /// </summary>
        public const string NOT = "0";

        /// <summary>
        /// 须要加密
        /// </summary>
        public const string NEED = "1";
    }
    #endregion

    public class WeiXinHelper
    {
        /// <summary>
        /// 发送文本消息给微信用户
        /// </summary>
        /// <param name="returnErrorMsg">当返回值为false时,返回的错误信息.</param>
        /// <param name="qyNoIds">用户的企业号的ID列表(多个用户之间用‘|’分隔)</param>
        /// <param name="message">发送的消息</param>
        /// <returns></returns>
        public static bool SendContent(out String returnErrorMsg, String qyNoIds, String message)
        {
            if (String.IsNullOrWhiteSpace(qyNoIds))
            {
                returnErrorMsg = "缺少微信用户";
                return false;
            }

            WeiXinService.MainService mainService = new WeiXinService.MainService();
            bool isSendMsgResult = false;
            bool isSendMsgResultSpecified = false;
            mainService.SendMsg(qyNoIds,
                                     null,
                                     null,
                                     WeiXinMessageType.TEXT,
                                     message,
                                     WeiXinMessageEncription.NOT,
                                     out isSendMsgResult,
                                     out isSendMsgResultSpecified,
                                     out returnErrorMsg);

            if isSendMsgResult&& isSendMsgResultSpecified,
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

注:

(1).这里调用WCF时不像Asp.Net或者WinForm下。使用Client来调用。而是要使用MainService实例来调用。为什么使用MainService呢?由于WCF的微信企业号服务主类就是MainService.

(2).MainService中的SendMsg方法。原来有一个bool的返回值,可是这里不见了。事实上不是不见了,而是以out的形式输出了。

即isSendMsgResult和isSendMsgResultSpecified.当中isSendMsgResultSpecified是引用时自己主动带入的參数。当isSendMsgResult和isSendMsgResultSpecified都为true时。表示成功。

三.生成应用

1.在生成应用之前,一定记得设置应用的api级别。并配置所须要的相关权限,详细见以下的图。

注:假设没有配置Android的API级别,将会导致应用安装时程序包解析失败而无法安装。

注:这里须要配置ACCESS_WIFI_STATE和INTERNAL的权限,假设没有配置将会导致数据库连接和微信通知时失败,提示connect refuse等字样。

2.一定记得设置成Release下生成应用。在Debug下生成的应用可能正常执行的,在Release下可能会失败,最常见的就是权限没有设置导致的。

3.应用可能须要配置合适的屏幕尺寸,否则在小米盒子中会无法显示,比方一片黑。

3.打包应用

转载请注明出处http://blog.csdn.net/xxdddail/article/details/46707481。

时间: 2024-11-07 19:59:16

C#的Xamarin开发小米盒子应用并以WCF实现微信通知的相关文章

Android 小米盒子使用电视特性标签

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 写博文也有一两年了,总体感觉,特意去写一篇很中规中矩的文章,确实需要很多准备以及清晰的条理,往往这需要很多时间和精力,有时效果也确实没那么好. 相

Android 小米盒子游戏手柄按键捕获

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 终于又告一段落,可以好好休息一下了. 以前,提及身体,总是再坚持一下,就这样坚持了 15 年. 现在,提及生命,不敢再坚持一下,还是休养一段,再整

xamarin开发android收集的一些工具

xamarin开发android收集的一些工具 工欲善其事,必先利其器,从16年下半年开始做xamarin相关的开发,平时使用的一些工具和google插件给大家分享一下,都有下载地址,持续更新. Visual Studio Emulator for Android 通过 Visual Studio 实现最佳Android模拟器(微软家的) Genymotion Android模拟器(google家的) Xamarin Live Player xamarin开发android.ios实时预览器 C

Xamarin开发Android时Visual Studio 2012没有智能提示解决办法

Most of the people who work with Xamarin’s Mono for Android in Visual Studio 2012 face a bug where Intellisense doesn’t work for AXML in source view. One of the fix which worked for me is mentioned below. Launch Visual Studio 2012 Open a solution wit

手柄连接小米3,小米3连接小米盒子

小米3 通过USB-OTG 线连接罗技F310手柄,在打开小米盒子的Miracast ,用小米3手机连接投影屏幕到电视机上. 下载现代战争4(支持手柄),就可以拿着手柄对着电视打游戏了.. 关于手柄 不晓得其他手柄支持不支持,反正我的罗技F310 一百三十多,和北通的50块的手柄是一样的,当时买罗技的就是为了兼容性好点. 关于Miracast 的延迟. Miracast  玩游戏,延迟还是比较大的.可以设置一下,低延迟,当然画面质量也会下降.最近看了未来的几种低延迟的技术,用的50Ghz频段.估

小米盒子救砖之路

我的小米盒子1S标准版(MDZ-06-AA),因为刷了石头的ROM,一开始还好用 没过几天各种卡顿,实在受不了,就用了一下石头的系统还原功能了,好了,悲剧发生了! 还原过的版本的根本进不了系统,就是那个石头智障工程师设计的强制用户必须用帐户登录,登录试了N次进不了,注册帐户也一样,快速注册也一样,哎,石头ROM根本没考虑过用户的感受,这系统没有开启USB调度的功能,也就意味着你刷了它的系统,再想刷,不说没门,但很难!如果你的小米是MDZ-09-AA,后面有USB接口,那就下载一个小米的UPDAT

Xamarin开发Android应用打包apk

Visual Studio中用Xamarin开发Android应用,生成apk文件有3种方法 1.debug时,代码目录下bin\Debug中会自动生成调试用***-Signed.apk文件,但是文件Size非常大,不建议使用. 2.Release时,“部署”勾选√,生成--部署解决方案后,代码目录下bin\Release中会自动生成部署用***-Signed.apk文件,文件Size比较小. 3.自己打包,工具--Publish Android Application,一步一步设置打包,文件S

C#使用Xamarin开发可移植移动应用进阶篇(8.打包生成安卓APK并精简大小),附源码

前言 系列目录 C#使用Xamarin开发可移植移动应用目录 源码地址:https://github.com/l2999019/DemoApp 可以Star一下,随意 - - 说点什么.. 嗯,前面讲了那么多,是时候生成一个APK在真机上玩玩了. 今天的学习内容? 也只讲一个,如何打包生成安卓可安装的APK并精简大小. 正文 我记得,之前在写安卓方面的文章的时候,有人就问过我.Xamarin.Android为什么打包出来这么大?随便一个HelloWord就20-30MB? 嗯..今天我们就来解决

小米盒子连接老式电脑显示器(VGA接口)

家里闲置一台老式显示器,只有VGA接口,无HDMI高清接口; 小米盒子上有三个输出接口: 一个HDMI高清接口:HDMI接口输出的有音频信号和视频信号,现在买的电视机一般都有HDMI高清接口: 一个AV接口:同样带有音频信号和视频信号,这个通常用来连接老式的电视机: 一个USB:Micro-USB接口:使用一根OTG连接线连接后,可以插U盘播放U盘中视频 我的显示器要想用上小米盒子,需要一根HDMI转VGA的转换器: 在网上找到这样的东东:   产品页面上强调如果信号源电力不足,需要使用micr