C#的Xamarin开发小米盒子应用并以WCF实现微信通知
对于熟悉C#语言的开发人员而言,用Xamarin开发Android应用也是一个不错的选择。小米盒子是Android系统。当然也就能够使用Xamarin来开发。首选来看效果图。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHhkZGRhaWw=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
注:(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的字符集,所以我们的应用也需需有这种字符集支持,为此须要给应用加一个配置,见下图。项目->右键->属性,然后按下图配置。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHhkZGRhaWw=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
注: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引用。见下图。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHhkZGRhaWw=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
这时在我们的项目中,会多一个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。
C#的Xamarin开发小米盒子应用并以WCF实现微信通知的更多相关文章
- xamarin开发android收集的一些工具
xamarin开发android收集的一些工具 工欲善其事,必先利其器,从16年下半年开始做xamarin相关的开发,平时使用的一些工具和google插件给大家分享一下,都有下载地址,持续更新. Vi ...
- Android 小米盒子游戏手柄按键捕获 - 能获取到的 home 键依旧是个痛
Android 小米盒子游戏手柄按键捕获 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 ...
- Xamarin开发Android应用打包apk
Visual Studio中用Xamarin开发Android应用,生成apk文件有3种方法 1.debug时,代码目录下bin\Debug中会自动生成调试用***-Signed.apk文件,但是文件 ...
- 老司机学新平台 - Xamarin开发环境及开发框架初探
随着被微软收购,最近一年间,Xamarin的火爆程度与日俱增.免费.更好的VS2015集成.更好的模拟器,甚至,在windows上运行和调试iOS平台程序,让我这样接触了十几年.NET平台的老司机,即 ...
- Xamarin Android教程如何使用Xamarin开发Android应用
Xamarin Android教程如何使用Xamarin开发Android应用 在了解了Xamarin和Andriod系统之后,下面我们需要了解一下如何使用这些工具和系统来开发我们的应用程序. And ...
- Xamarin开发Android笔记:背景操作
使用Xamarin开发Android UI的时可能会遇到一些场景背景的问题,虽然可以利用多层或直接使用图片背景来完成,但这样会增加不少的资源消耗,最终导致内存溢出的情况.最好的方法还是利用内部方法或代 ...
- Xamarin开发Anroid应用介绍
第1章 Xamarin开发Anroid应用介绍 如今智能手机已经盛行了好几年,而针对这些智能手机的软件开发也变得异常火热.但是在Android平台下只能使用Java开发,iOS平台下也只能使用Obj ...
- 小米盒子连接老式电脑显示器(VGA接口)
家里闲置一台老式显示器,只有VGA接口,无HDMI高清接口; 小米盒子上有三个输出接口: 一个HDMI高清接口:HDMI接口输出的有音频信号和视频信号,现在买的电视机一般都有HDMI高清接口: 一个A ...
- 【Xamarin挖墙脚系列:Xamarin开发环境配置需求】
原文:[Xamarin挖墙脚系列:Xamarin开发环境配置需求] 前言 因为操作的全是大块头,加大你们的内存,CPU网上飙.... 卤煮的机器配置 最近的版本部署包,百度云离线下载:版本:Xama ...
随机推荐
- unity中绘制战争迷雾
接上一篇中说的游戏,我们已经实现了client.host上的一个物体可见不可见的行为.之后我们可以加入类似检查两个单位之间的距离.或是两个单位之间有无阻挡物来进一步实现游戏机制. 在这篇随笔中我会首先 ...
- Nginx的主要配置参数说明
#定义Nginx运行的用户和用户组user www www; #nginx进程数,建议设置为等于CPU总核心数.worker_processes 8; #全局错误日志定义类型,[ debug | in ...
- mongoDB的简单使用
1.客户端连接: ./mongo 2.数据库 一个mongodb中可以建立多个数据库. MongoDB的默认数据库为"db",该数据库存储在data目录中. MongoDB的单个实 ...
- python3,判断,循环练习1
1.使用while循环输出1 2 3 4 5 6 8 9 10 i = 1 while i <= 10: if i == 7: i += 1 print(end=' ') continue pr ...
- java servlet输出数据
httpServletResponse.setContentType("text/html;charset=UTF-8"); httpServletResponse.getWrit ...
- 1.shell快速入门
shell是什么?shell是一个命令行解释器,它提供了一个像linux内核发送请求以便运行程序的界面系统程序,用户可以用shell来启动.挂起.停止甚至是编写一些程序.说白了,shell就是用来和内 ...
- k8s通过label来控制pod的位置
默认情况下,scheduler会将pod调度到所有可用的Node,不过有些情况我们希望将 Pod 部署到指定的 Node,比如将有大量磁盘 I/O 的 Pod 部署到配置了 SSD 的 Node:或者 ...
- rabbitmq安装-Erlang
安装Erlang Install Erlang from the Erlang Solutions repository or Follow the instructions under " ...
- 拒绝平庸——浅谈WEB登录页面设计
用户活跃度是检验产品成功与否的重要指标之一,传统行业的商家极为重视门面的装潢,因为一个好的门面可以聚集人气,招揽更多的顾客.古时候的大户人家院子门口的石狮子或其他的摆件的摆放极为讲究,有一定的风水学说 ...
- 关于oracle的sqlplus的另一些小技巧
执行脚本的命令在上一节已经讲过,不再重复. sqlplus user/password@ip:port/servicename @/path/sqltest.sql; sqltest的内容及注释: - ...