跨过几个坑,终于完成了我的第一个Xamarin Android App!

  时间过得真快,距离上次发随笔又是一年多。作为上次发的我的第一个WP8.1应用总结的后继,这次同样的主要功能,改为实现安卓版APP。前几个月巨硬收购Xamarin,把Xamarin集成到VS里了,大大方便了我广大.net码农。由于年初脱了WP的坑,换了个安卓低端机,想着什么时候装Xamarin开发个App玩玩。

  上个月笔记本100G的C盘莫名其妙快满了,趁着重装系统的机会,安装了VS2015 with sp3,下载开发Android App需要的各种东东。这里要感谢【C#】VS2015开发环境的安装和配置系列文章,2016-07-03更新的,已经算是最新的vs2015 with update3的安装说明了。可惜看到这篇文章还是有点相见恨晚,文章里的流程是先下载安装JDK和Android SDK等,最后安装VS,我反过来做,浪费了一些时间。PS:对于使用Hyper-V的同学,可以使用VS自带的安卓模拟器,省却了下载和安装GOOGLE模拟器的一堆时间,据说GOOGLE模拟器还挺坑。。。

================================扯得太多,言归正传======================================

  App项目用的是VS里的Android Blank App,先上个图让大家看看我手机上的显示效果,自己用就不需要那么华丽丽了(关键是不会。。。)。

  Android App使用的是显示与逻辑分离的设计模式,虽然我基本是做Winform的,也是基本能看懂的。Resources\layout文件夹里放视图文件,而代码逻辑文件放在最外层,整个项目的结构如下图:

  这个App主界面使用的是GridLayout进行垂直布局,用法类似于HTML中的Table和WPF中的Grid,代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="horizontal"
 6     android:paddingLeft="10dp"
 7     android:paddingRight="10dp"
 8     android:rowCount="6"
 9     android:columnCount="2">
10     <TextView
11         android:id="@+id/tvMachineCode"
12         android:layout_width="wrap_content"
13         android:layout_marginRight="5dp"
14         android:textSize="20sp"
15         android:layout_marginTop="50dp"
16         android:text="机器码" />
17     <EditText
18         android:id="@+id/txtMachineCode"
19         android:textSize="20sp"
20         android:maxLength ="20"
21         android:layout_marginTop="50dp"
22         android:layout_width="fill_parent" />
23     <TextView
24         android:id="@+id/tvActiviationCode"
25         android:layout_width="wrap_content"
26         android:layout_marginRight="5dp"
27         android:textSize="20sp"
28         android:layout_marginTop="30dp"
29         android:text="激活码" />
30     <EditText
31         android:id="@+id/txtActiviationCode"
32         android:textSize="20sp"
33         android:layout_marginTop="30dp"
34         android:layout_width="fill_parent" />
35     <Button
36         android:id="@+id/btnGetActiviationCode"
37         android:layout_marginTop="30dp"
38         android:layout_columnSpan="2"
39         android:layout_width="match_parent"
40         android:text="获取激活码" />
41     <Button
42         android:id="@+id/btnScanQRCode"
43         android:layout_columnSpan="2"
44         android:layout_width="match_parent"
45         android:text="扫描二维码" />
46     <Button
47         android:id="@+id/btnReadQRCode"
48         android:layout_columnSpan="2"
49         android:layout_width="match_parent"
50         android:text="读取二维码" />
51   <Button
52       android:id="@+id/btnCopy"
53       android:layout_columnSpan="2"
54       android:layout_width="match_parent"
55       android:text="复制激活码" />
56   <Button
57       android:id="@+id/btnShare"
58       android:layout_columnSpan="2"
59       android:layout_width="match_parent"
60       android:text="发送激活码" />
61     <Button
62         android:id="@+id/btnClear"
63         android:layout_columnSpan="2"
64         android:layout_width="match_parent"
65         android:text="清除" />
66 </GridLayout>

Main.axml

  界面设计好之后,开始写逻辑代码。App默认是从MainActivity开始启动(JAVA开发可以在Properties\AndroidManifest.xml中修改,有谁知道Xamarin里是怎么改的?)。开始实现第一个按钮的功能,自我感觉还是比较容易的,基本可以直接复制粘贴我Winform里的代码,然而,我发现掉到第一个坑里去了。先看看从Winform里复制来的字符串取MD5的代码,这个在VS自带的模拟器中执行是正常的,得到的结果与Winform一致,但安装到手机里得到的就不对了。

1         private string MD5(string str, bool clearsplitter = true, bool islower = true)
2         {
3             var md5 = MD5CryptoServiceProvider.Create();
4             var output = md5.ComputeHash(Encoding.Default.GetBytes(str));
5             StringBuilder strbvalue = new StringBuilder(BitConverter.ToString(output).Replace("-", string.Empty).Substring(8, 16));
6             if (!clearsplitter)
7                 strbvalue.Insert(12, ‘-‘).Insert(8, ‘-‘).Insert(4, ‘-‘);
8             return islower ? strbvalue.ToString().ToLower() : strbvalue.ToString().ToUpper();
9         }

 上网查了下,也问了下别人,电脑里Encoding.Default用的编码是GB2312,而手机里可能是ASCII。由于不能修改之前的代码,只能改这个了,把Encoding.Default改成了Encoding.GetEncoding("gb2312"),结果出乎预料,竟然闪退了。。。又上网搜了下,需要引用Xamarin安装自带的I18N.CJK,总算是搞定了第一个按钮。以下是【获取激活码】和【清除】的代码:

        private void Btngetactiviationcode_Click(object sender, EventArgs e)
        {
            string strerr = ValidateFormat(txtMachineCode.Text);
            if (strerr != string.Empty)
            {
                var dlg = new AlertDialog.Builder(this).SetTitle("警告")
                    .SetMessage("输入的机器码格式不正确!\n" + strerr);
                dlg.Show();
                Btnclear_Click(this, null);
                return;
            }
            txtActiviationCode.Text = GetActiveCode(txtMachineCode.Text);
        }

        private void Btnclear_Click(object sender, EventArgs e)
        {
            txtMachineCode.Text = txtActiviationCode.Text = string.Empty;
        }

        private string GetActiveCode(string machinecode)
        {
            string guid = "cd89e66c-b897-4ed8-a19f-ef5a30846f0a";
            return MD5(machinecode + MD5(guid, false, false), false, false);
        }

        private string MD5(string str, bool clearsplitter = true, bool islower = true)
        {
            var md5 = MD5CryptoServiceProvider.Create();
            var output = md5.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(str));
            StringBuilder strbvalue = new StringBuilder(BitConverter.ToString(output).Replace("-", string.Empty).Substring(8, 16));
            if (!clearsplitter)
                strbvalue.Insert(12, ‘-‘).Insert(8, ‘-‘).Insert(4, ‘-‘);
            return islower ? strbvalue.ToString().ToLower() : strbvalue.ToString().ToUpper();
        }

【获取激活码】和【清除】

  这个App的主要便利用途就是能够扫描和识别二维码,上网搜了下,使用ZXing库会比较简单,它有个.net移动开发版本叫ZXing.Net.Mobile,可以使用Nuget直接下载添加引用,由于它依赖于Xamarin.Android.Support.v4,所以也要一起下载安装。直接按照ZXing.Net.Mobile官网上的扫描二维码示例代码,就做好了最简单的二维码扫描功能。注意:要在OnCreate方法里先初始化一下:

1     MobileBarcodeScanner.Initialize(Application);
1         private async void Btnscanqrcode_Click(object sender, EventArgs e)
2         {
3             var scanner = new ZXing.Mobile.MobileBarcodeScanner();
4             var result = await scanner.Scan();
5             if (result == null)
6                 return;
7             txtMachineCode.Text = result.Text.Trim();
8             Btngetactiviationcode_Click(this, null);
9         }

  完成扫描二维码的功能,顿时信心大增,以为识别图片中的二维码也很简单,结果发现又掉第二个坑里去了。原来,ZXing.Net.Mobile里没有现成简单的识别二维码的方法,只查到可以用IBarcodeReader.Decode()方法来识别,然而它第一个参数byte[] rawRGB是个什么鬼?为毛不能提供一个Bitmap让我爽一下?!去网上搜JAVA版的都是传递Bitmap对象,再去看了下ZXing.Net.Mobile的源码,竟然是有些项目类型是Bitmap对象,有些是byte[]。没时间深究,我还是自己来弄个byte[]吧。

  印象中看到过一篇教程里介绍过这个方法,说rawRGB参数指的是每个像素点的RGB值数组,而不是图像文件的二进制数组,这就要读取图像中的所有点的颜色值到数组里里再传递了。

 1         private void Btnreadqrcode_Click(object sender, EventArgs e)
 2         {
 3             Intent = new Intent();
 4             //从文件浏览器和相册等选择图像文件
 5             Intent.SetType("image/*");
 6             Intent.SetAction(Intent.ActionGetContent);
 7             StartActivityForResult(Intent, 1);
 8         }
 9
10         protected override void OnActivityResult(int requestCode, [GeneratedEnum] Android.App.Result resultCode, Intent data)
11         {
12             base.OnActivityResult(requestCode, resultCode, data);
13             if(requestCode == 1 && resultCode == Android.App.Result.Ok && data != null)
14             {
15                 // create a barcode reader instance
16                 IBarcodeReader reader = new BarcodeReader();
17                 // load a bitmap
18                 int width = 0, height = 0;
19                 //像素颜色值列表(注意:一个像素的每个颜色值都是一个列表中单独的元素,
20                 //后面将会把像素颜色值转换成ARGB32格式的颜色,每个像素颜色值就有4个元素加入到列表中)
21                 List<byte> pixelbytelist = new List<byte>();
22                 try
23                 {
24                     //根据选择的文件路径生成Bitmap对象
25                     using (Bitmap bmp = Android.Provider.MediaStore.Images.Media.GetBitmap(ContentResolver, data.Data))
26                     {
27                         width = bmp.Width; //图像宽度
28                         height = bmp.Height;  //图像高度
29                         // detect and decode the barcode inside the bitmap
30                         bmp.LockPixels();
31                         int[] pixels = new int[width * height];
32                         //一次性读取所有像素的颜色值(一个整数)到pixels
33                         bmp.GetPixels(pixels, 0, width, 0, 0, width, height);
34                         bmp.UnlockPixels();
35                         for (int i = 0; i < pixels.Length; i++)
36                         {
37                             int p = pixels[i];  //取出一个像素颜色值
38                             //将像素颜色值中的alpha颜色(透明度)添加到列表
39                             pixelbytelist.Add((byte)Color.GetAlphaComponent(p));
40                             //将像素颜色值中的红色添加到列表
41                             pixelbytelist.Add((byte)Color.GetRedComponent(p));
42                             //将像素颜色值中的绿色添加到列表
43                             pixelbytelist.Add((byte)Color.GetGreenComponent(p));
44                             //将像素颜色值中的蓝色添加到列表
45                             pixelbytelist.Add((byte)Color.GetBlueComponent(p));
46                         }
47                     }
48                     //识别
49                     var result = reader.Decode(pixelbytelist.ToArray(), width, height, RGBLuminanceSource.BitmapFormat.ARGB32);
50                     if (result != null)
51                     {
52                         txtMachineCode.Text = result.Text.Trim();
53                         Btngetactiviationcode_Click(this, null);
54                     }
55                     else
56                         Toast.MakeText(this, "未能识别到二维码!", ToastLength.Short).Show();
57                 }
58                 catch (Exception ex)
59                 {
60                     var dlg = new AlertDialog.Builder(this).SetTitle("警告")
61                         .SetMessage("获取图像时发生错误!\n" + ex.ToString());
62                     dlg.Show();
63                 }
64             }
65         }

  上面就完成了识别二维码的功能,不过上面红色文字那里又出现个只在手机上出现的诡异问题,识别出来的二维码后面会多出一个不可见的字符,它会影响EditText中Text的长度,但不影响Text的值,可以被删除,删除前后计算出的激活码是相同的。没有去看源码,不知道怎么产生的,有人知道吗?

  后面的复制激活码和发送激活码比较简单,都是直接找的网上的代码,调用系统功能来做。

 1         private void Btncopy_Click(object sender, EventArgs e)
 2         {
 3             ClipboardManager clip = (ClipboardManager)GetSystemService(ClipboardService);
 4             StringBuilder strbcontent = new StringBuilder();
 5             strbcontent.AppendLine("机器码:" + txtMachineCode.Text)
 6                 .AppendLine("激活码:" + txtActiviationCode.Text);
 7             ClipData clipdata = ClipData.NewPlainText("激活码", strbcontent.ToString());
 8             clip.PrimaryClip = clipdata;
 9             Toast.MakeText(this, "激活码已复制到剪贴板", ToastLength.Short).Show();
10         }
11
12         private void Btnshare_Click(object sender, EventArgs e)
13         {
14             if (string.IsNullOrWhiteSpace(txtActiviationCode.Text))
15             {
16                 var dlg = new AlertDialog.Builder(this).SetTitle("警告")
17                     .SetMessage("请先获取激活码!");
18                 dlg.Show();
19                 return;
20             }
21             string strerr = ValidateFormat(txtMachineCode.Text);
22             if (strerr != string.Empty)
23             {
24                 var dlg = new AlertDialog.Builder(this).SetTitle("警告")
25                     .SetMessage("输入的机器码格式不正确!\n" + strerr);
26                 dlg.Show();
27                 return;
28             }
29             Intent intent = new Intent(Intent.ActionSend);
30             intent.SetType("text/plain");//所有可以分享文本的app
31             StringBuilder strbcontent = new StringBuilder();
32             strbcontent.AppendLine("机器码:" + txtMachineCode.Text)
33                 .AppendLine("激活码:" + txtActiviationCode.Text);
34             intent.PutExtra(Intent.ExtraText, strbcontent.ToString());
35             StartActivity(Intent.CreateChooser(intent, "发送激活码"));
36         }
37
38         private string ValidateFormat(string str)
39         {
40             if(str.Length<19)
41                 return "输入的格式不正确";
42             if (str.Length != 19)
43                 str = str.Substring(0, 19);
44             string[] strs = str.Split(‘-‘);
45             if (strs.Length != 4)
46                 return "不能分隔为4组";
47             foreach (string s in strs)
48             {
49                 if (s.Length != 4)
50                     return s + "的长度不是4";
51                 if (!System.Text.RegularExpressions.Regex.IsMatch(s, "^[A-F0-9]{4}$"))
52                     return s + "的格式不正确";
53             }
54             return string.Empty;
55         }

【复制激活码】和【发送激活码】

  断断续续写了几个晚上,终于写完这篇随笔了。在眼睛彻底睁不开之前赶紧贴上完整代码。

  1 using System;
  2 using Android.App;
  3 using Android.Content;
  4 using Android.Runtime;
  5 using Android.Views;
  6 using Android.Widget;
  7 using Android.OS;
  8 using System.Text;
  9 using System.Security.Cryptography;
 10 using ZXing.Mobile;
 11 using Android.Graphics;
 12 using ZXing;
 13 using Android.Database;
 14 using System.Collections.Generic;
 15
 16 namespace FMSKeygen_Android
 17 {
 18     [Activity(Label = "流程管理系统注册机", MainLauncher = true, Icon = "@drawable/icon")]
 19     public class MainActivity : Activity
 20     {
 21         private EditText txtMachineCode = null;
 22         private EditText txtActiviationCode = null;
 23
 24         protected override void OnCreate(Bundle bundle)
 25         {
 26             base.OnCreate(bundle);
 27
 28             // Set our view from the "main" layout resource
 29             SetContentView(Resource.Layout.Main);
 30
 31             // 初始化二维码扫描仪,后面要用到
 32             MobileBarcodeScanner.Initialize(Application);
 33
 34             txtMachineCode = FindViewById<EditText>(Resource.Id.txtMachineCode);
 35             //设置自动转换小写字母为大写
 36             txtMachineCode.SetFilters(new Android.Text.IInputFilter[] { new Android.Text.InputFilterAllCaps() });
 37             txtActiviationCode = FindViewById<EditText>(Resource.Id.txtActiviationCode);
 38             //取消对验证码文本框的所有按键监听
 39             txtActiviationCode.KeyListener = null;
 40             Button btnclear = FindViewById<Button>(Resource.Id.btnClear);
 41             btnclear.Click += Btnclear_Click;
 42             Button btngetactiviationcode = FindViewById<Button>(Resource.Id.btnGetActiviationCode);
 43             btngetactiviationcode.Click += Btngetactiviationcode_Click;
 44             Button btnscanqrcode = FindViewById<Button>(Resource.Id.btnScanQRCode);
 45             btnscanqrcode.Click += Btnscanqrcode_Click;
 46             Button btncopy = FindViewById<Button>(Resource.Id.btnCopy);
 47             btncopy.Click += Btncopy_Click;
 48             Button btnreadqrcode = FindViewById<Button>(Resource.Id.btnReadQRCode);
 49             btnreadqrcode.Click += Btnreadqrcode_Click;
 50             Button btnshare = FindViewById<Button>(Resource.Id.btnShare);
 51             btnshare.Click += Btnshare_Click;
 52         }
 53
 54
 55         private void Btnshare_Click(object sender, EventArgs e)
 56         {
 57             if (string.IsNullOrWhiteSpace(txtActiviationCode.Text))
 58             {
 59                 var dlg = new AlertDialog.Builder(this).SetTitle("警告")
 60                     .SetMessage("请先获取激活码!");
 61                 dlg.Show();
 62                 return;
 63             }
 64             string strerr = ValidateFormat(txtMachineCode.Text);
 65             if (strerr != string.Empty)
 66             {
 67                 var dlg = new AlertDialog.Builder(this).SetTitle("警告")
 68                     .SetMessage("输入的机器码格式不正确!\n" + strerr);
 69                 dlg.Show();
 70                 return;
 71             }
 72             Intent intent = new Intent(Intent.ActionSend);
 73             intent.SetType("text/plain");//所有可以分享文本的app
 74             StringBuilder strbcontent = new StringBuilder();
 75             strbcontent.AppendLine("机器码:" + txtMachineCode.Text)
 76                 .AppendLine("激活码:" + txtActiviationCode.Text);
 77             intent.PutExtra(Intent.ExtraText, strbcontent.ToString());
 78             StartActivity(Intent.CreateChooser(intent, "发送激活码"));
 79         }
 80
 81         private string ValidateFormat(string str)
 82         {
 83             if(str.Length<19)
 84                 return "输入的格式不正确";
 85             if (str.Length != 19)
 86                 str = str.Substring(0, 19);
 87             string[] strs = str.Split(‘-‘);
 88             if (strs.Length != 4)
 89                 return "不能分隔为4组";
 90             foreach (string s in strs)
 91             {
 92                 if (s.Length != 4)
 93                     return s + "的长度不是4";
 94                 if (!System.Text.RegularExpressions.Regex.IsMatch(s, "^[A-F0-9]{4}$"))
 95                     return s + "的格式不正确";
 96             }
 97             return string.Empty;
 98         }
 99
100         private void Btnreadqrcode_Click(object sender, EventArgs e)
101         {
102             Intent = new Intent();
103             //从文件浏览器和相册等选择图像文件
104             Intent.SetType("image/*");
105             Intent.SetAction(Intent.ActionGetContent);
106             StartActivityForResult(Intent, 1);
107         }
108
109         protected override void OnActivityResult(int requestCode, [GeneratedEnum] Android.App.Result resultCode, Intent data)
110         {
111             base.OnActivityResult(requestCode, resultCode, data);
112             if(requestCode == 1 && resultCode == Android.App.Result.Ok && data != null)
113             {
114                 // create a barcode reader instance
115                 IBarcodeReader reader = new BarcodeReader();
116                 // load a bitmap
117                 int width = 0, height = 0;
118                 //像素颜色值列表(注意:一个像素的每个颜色值都是一个列表中单独的元素,
119                 //后面将会把像素颜色值转换成ARGB32格式的颜色,每个像素颜色值就有4个元素加入到列表中)
120                 List<byte> pixelbytelist = new List<byte>();
121                 try
122                 {
123                     //根据选择的文件路径生成Bitmap对象
124                     using (Bitmap bmp = Android.Provider.MediaStore.Images.Media.GetBitmap(ContentResolver, data.Data))
125                     {
126                         width = bmp.Width; //图像宽度
127                         height = bmp.Height;  //图像高度
128                         // detect and decode the barcode inside the bitmap
129                         bmp.LockPixels();
130                         int[] pixels = new int[width * height];
131                         //一次性读取所有像素的颜色值(一个整数)到pixels
132                         bmp.GetPixels(pixels, 0, width, 0, 0, width, height);
133                         bmp.UnlockPixels();
134                         for (int i = 0; i < pixels.Length; i++)
135                         {
136                             int p = pixels[i];  //取出一个像素颜色值
137                             //将像素颜色值中的alpha颜色(透明度)添加到列表
138                             pixelbytelist.Add((byte)Color.GetAlphaComponent(p));
139                             //将像素颜色值中的红色添加到列表
140                             pixelbytelist.Add((byte)Color.GetRedComponent(p));
141                             //将像素颜色值中的绿色添加到列表
142                             pixelbytelist.Add((byte)Color.GetGreenComponent(p));
143                             //将像素颜色值中的蓝色添加到列表
144                             pixelbytelist.Add((byte)Color.GetBlueComponent(p));
145                         }
146                     }
147                     //识别
148                     var result = reader.Decode(pixelbytelist.ToArray(), width, height, RGBLuminanceSource.BitmapFormat.ARGB32);
149                     if (result != null)
150                     {
151                         txtMachineCode.Text = result.Text.Trim();
152                         Btngetactiviationcode_Click(this, null);
153                     }
154                     else
155                         Toast.MakeText(this, "未能识别到二维码!", ToastLength.Short).Show();
156                 }
157                 catch (Exception ex)
158                 {
159                     var dlg = new AlertDialog.Builder(this).SetTitle("警告")
160                         .SetMessage("获取图像时发生错误!\n" + ex.ToString());
161                     dlg.Show();
162                 }
163             }
164         }
165
166         private void Btncopy_Click(object sender, EventArgs e)
167         {
168             ClipboardManager clip = (ClipboardManager)GetSystemService(ClipboardService);
169             StringBuilder strbcontent = new StringBuilder();
170             strbcontent.AppendLine("机器码:" + txtMachineCode.Text)
171                 .AppendLine("激活码:" + txtActiviationCode.Text);
172             ClipData clipdata = ClipData.NewPlainText("激活码", strbcontent.ToString());
173             clip.PrimaryClip = clipdata;
174             Toast.MakeText(this, "激活码已复制到剪贴板", ToastLength.Short).Show();
175         }
176
177         private async void Btnscanqrcode_Click(object sender, EventArgs e)
178         {
179             var scanner = new ZXing.Mobile.MobileBarcodeScanner();
180             var result = await scanner.Scan();
181             if (result == null)
182                 return;
183             txtMachineCode.Text = result.Text.Trim();
184             Btngetactiviationcode_Click(this, null);
185         }
186
187         private void Btngetactiviationcode_Click(object sender, EventArgs e)
188         {
189             string strerr = ValidateFormat(txtMachineCode.Text);
190             if (strerr != string.Empty)
191             {
192                 var dlg = new AlertDialog.Builder(this).SetTitle("警告")
193                     .SetMessage("输入的机器码格式不正确!\n" + strerr);
194                 dlg.Show();
195                 Btnclear_Click(this, null);
196                 return;
197             }
198             txtActiviationCode.Text = GetActiveCode(txtMachineCode.Text);
199         }
200
201         private void Btnclear_Click(object sender, EventArgs e)
202         {
203             txtMachineCode.Text = txtActiviationCode.Text = string.Empty;
204         }
205
206         private string GetActiveCode(string machinecode)
207         {
208             string guid = "cd89e66c-b897-4ed8-a19f-ef5a30846f0a";
209             return MD5(machinecode + MD5(guid, false, false), false, false);
210         }
211
212         private string MD5(string str, bool clearsplitter = true, bool islower = true)
213         {
214             var md5 = MD5CryptoServiceProvider.Create();
215             var output = md5.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(str));
216             StringBuilder strbvalue = new StringBuilder(BitConverter.ToString(output).Replace("-", string.Empty).Substring(8, 16));
217             if (!clearsplitter)
218                 strbvalue.Insert(12, ‘-‘).Insert(8, ‘-‘).Insert(4, ‘-‘);
219             return islower ? strbvalue.ToString().ToLower() : strbvalue.ToString().ToUpper();
220         }
221     }
222 }

完整代码

  碎觉。。

时间: 2024-10-10 11:19:35

跨过几个坑,终于完成了我的第一个Xamarin Android App!的相关文章

跨过Django的坑

在最近的Django的学习中,慢慢的开始踩坑,开此栏,专为收纳Django的坑,在以后的学习中以便警示.(使用工具为pycharm专业版2018.2.4,python3.5.2,Django版本2.1.3) 1.关于提取表单的数据. 在前端通过表单提交数据,请求为post的请求,method="post",这里的post经测试,不用区分大小写: 1 <form action="index/" method="post"> #这里不用区

Android App引导页这些坑你自己犯过吗?

场景:測试机:华为荣耀6x 今天我自己掉入一个非常蠢蠢的坑,一个引导页搞了20多分钟.无论我怎么測试用真机还是模拟器都无法执行,可是我写的demo全然没问题,好无语,我都怀疑我是不是搞android,我去.一个简单的问题都不能解决?后来看了下自己真的傻逼了无语! 看下图 挖坑1 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMTU5NTAzMjU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dis

避免踩坑:易盾安全老司机起底Android九大漏洞,附解决建议

Android应用会遇到各种各样的漏洞,如何从细节上了解各种安全隐患,积极采取适当的防御措施便变得尤为重要.为了让大家对Android漏洞有一个非常全面的认识,网易云易盾资深安全工程师徐从祥为大家详细解读常见九大的Android漏洞,供各位学习参考.(如果下面干货内容没有让各位尽兴,欢迎来官网申请相关产品试用,面对面交流,保证解决你的安全难题. ? 第一大类:AndroidManifest配置相关的风险或漏洞 程序可被任意调试 风险详情:安卓应用apk配置文件Android Manifest.x

Microsoft Visual Studio 2015 下载、注册、安装过程、功能列表、问题解决

PS:请看看回复.可能会有文章里没有提到的问题.也许会对你有帮助哦~ VS2015正式版出了,虽然没有Ultimate旗舰版,不过也是好激动的说.哈哈.可能有的小伙伴,由于工作环境不允许.或者害怕有什么问题.所以不敢安装vs2015.只能眼巴巴地干瞅着. 因此,我决定,冒一次重装系统的风险,试着安装一下,正好也试试什么序列号能用.希望这次牺牲能值得~~呵呵. 下载地址:Microsoft Visual Studio 2015 全版本+离线MSDN+全部插件 赶紧下载,打开,发现VS2015对安装

Xamarin for Visual Studio 破解日志

一.相关声明 本文涉及的 Xamarin 系列软件的版权为 Xamarin Inc. 所有 以本文涉及的思路和方法破解的软件,禁止用于商业用途 如无必要,学习和研究时最好以正版为准 团队或土豪等若觉得 Xamarin 非常适合自身的业务,请务必支持正版 本文禁止转载扩散 之后应该不会发相关破解了,太耗时间 二.相关背景 2.1 材料背景 2014年年底,微软在 Connect 开发者大会上宣布了一系列展望,其中就有一个是 Visual Studio "通用平台"(跨平台开发)的进程,在

Appium 走过的坑( Mac+java )--Android 篇

Apple的坑走完后,终于打开了界面,想想还是有点小激动的,然后进入了更坑的Android环境搭建. 如果你以为这环境就和Apple这样easy能解决(虽然不少坑 - -),那就大错特错,android环境等于另外一套东西,比Apple难弄多了,机制也很傻... 牢骚话少说,咱们来跨坑,第一个坑随即而来,之前我在说Apple环境时,下载安装完appium工具,Apple环境自动已经完善(前提是你已经安装完xcode).那么android环境应该怎么配置呢? 我就绕过我求寻真理的沼泽了,直接说怎么

pexpect 初坑

通过一个很坑的任务,最近认识了一个新坑: pexpect .其实基本的用法并不难,不过,我还是跟以前一样,把几个基本函数的坑蹚了个遍.有感而发,记录一下. 首先简单的介绍一下这个坑,哦不对,这个库.这是一个 linux 下做SSH 远程登录和操作的库.我们平时用 windows 连接linux 的话,一定很熟悉 SecureCRT ,putty 这样的工具,这些工具就是通过 SSH 做远程连接的.pexpect正是这样一个库,如果有兴趣的话,使用这个库就可以做出一个 SSH 连接的工具. 然后介

手机那点事!已有高人把常见的不常见的坑都给找出来了,我就随便转一下了

mobileTech A useful tools or tips list for mobile web application developing 这个项目收集移动端开发所需要的一些资源与小技巧 工具类网站 HTML5 与 CSS3 技术应用评估 各种奇妙的hack 几乎所有设备的屏幕尺寸与像素密度表 移动设备参数表 ios端移动设备参数速查 浏览器兼容表 移动设备查询器 移动设备适配库 移动设备适配库2 viewport与设备尺寸在线检测器 html5 移动端兼容性速查 在线转换字体 c

[移动端]移动端上遇到的各种坑与相对解决方案

mobileHack 这里收集了许多移动端上遇到的各种坑与相对解决方案 1.问题:手机端 click 事件会有大约 300ms 的延迟 原因:手机端事件 touchstart –> touchmove –> touchend or touchcancel –> click,因为在touch事件触发之后,浏览器要判断用户是否会做出双击屏幕的操作,所以会等待300ms来判断,再做出是否触发click事件的处理,所以就会有300ms的延迟 解决方法:使用touch事件来代替click事件,如