要开始开发Xamarin应用程序,首先需要安装Visual Studio或Xamarin Studio,并确保包含所有必要的Xamarin组件。对于本例,我们将使用Visual Studio。在这链接你可以一步一步地阅读如何下载和安装Xamarin应用程序的Visual Studio。
安装完成后,打开Visual Studio,按照以下步骤执行:
1.去File ->新建->项目。
2.创建手机应用(Xamarin.Forms)。
3.选择空白应用程序的模板安卓而且iOS平台和net标准代码共享策略。
该方案包含三个项目:
1.便携式类库(PCL)项目
可移植类库(Portable Class Library, PCL)是一种特殊类型的项目,可以跨Xamarin等不同的CLI平台使用。iOS和Xamarin。安卓,as well as WPF, Universal Windows Platform, and Xbox. The library can only utilize a subset of the complete .NET framework, limited by the platforms being targeted.
2.Android平台特定应用程序项目
安卓特定于平台的项目必须引用绑定Xamarin所需的程序集。Android平台SDK以及Core共享代码项目。
3.iOS平台专用应用项目
iOS特定于平台的项目必须引用绑定Xamarin所需的程序集。iOS平台SDK以及Core共享代码项目。
在便携式项目中主页所有主要列表都在这里,ProductItemPage在哪里显示所有产品的特定列表,EditModalPage是自定义弹出编辑列表/产品名称,MainListItem而且ProductListItem模型显示列表/产品的列表项,以及ScannerPreviewcustom视图控件。
ScannerPreview是继承自Xamarin.Forms.View控件的类,我们添加了一些额外的自定义属性和事件处理程序。稍后我们将实现自定义渲染器对于这门课的特定平台项目。
这里我们使用ScannerPreview控制ProductItemPage添加新项目或编辑现有项目。
“gridCamera”集装箱是我们要添加的地方吗ScannerPreview控件在此页面出现时从后面的代码中获取。
为此,我们将重写OnAppearing ()方法ProductItemPage.
protected override void onappear () {base. onappear ();if (scannerControl == null) {scannerControl = new ScannerPreview();//你可以从这里选择设备,或者你可以选择出现在这个页面上的每一个。默认为SelectFromList scannerControl。选择edDevice = ScanningDevice.MobileCamera; //Preview enable. Default is true //scannerControl.ScanningPreviewEnable = false; //Event that will be triggered when result is received scannerControl.ResultReceived += scannerControl_ResultReceived; //Event that will be triggered when connection state will be changed scannerControl.ConnectionStateChanged += scannerControl_ConnectionStateChanged; //Add this control in this content gridCamera.Children.Insert(1, scannerControl); /*If you use scanner in navigation page and you add another page in navigation stack(where you will use scanner control again) * from this page like Navigation.PushAsync(new AnotherPage()) please use this code before you navigate */ //if (scannerControl != null) //{ // scannerControl.ResultReceived -= scannerControl_ResultReceived; // scannerControl.ConnectionStateChanged -= scannerControl_ConnectionStateChanged; // gridCamera.Children.Remove(scannerControl); // scannerControl = null; //} //Navigation.PushAsync(new AnotherPage()); } }
与scannerControl.ToggleScanning ()我们开始或停止扫描取决于当前的状态。
与scannerControl.SelectDevice ()弹出窗口显示从那里我们可以选择哪个设备将用于扫描(MX扫描仪或移动相机)。
在这个项目中,我们将设置所有的设置,我们需要android平台(最低安卓版本,目标安卓版本,应用程序名称,包名..),要求我们需要的权限,为安卓平台添加资源,为安卓平台创建自定义渲染器等。必威随行版官网
首先我们检查一下相机此应用程序所需的权限。
接下来将在可绘制文件夹中添加必威随行版官网资源(我们在可移植项目中使用)。
在撰写本文档时,android平台上Xamarin表单的导航栏图标存在bug,这就是为什么在这个项目中我们有小的修改Toolbar.axml和导航页的自定义渲染器(CustomNavigationRenderer).
ScannerPreviewRenderer类的自定义呈现器扫描预览(PCL自定义控件)Android平台。
[assembly: Xamarin.Forms.ExportRenderer(typeof(CMBSDKShoppingCartForms. scannerpreview), typeof(CMBSDKShoppingCartForms. droid . scannerpreviewrenderer))]命名空间CMBSDKShoppingCartForms. droid . scanerpreviewrenderer)。Droid{公共类ScannerPreviewRenderer: ViewRenderer {private RelativeLayout rlMainContainer;私有ImageView ivPreview;public ScannerPreviewRenderer(Context Context): base(Context) {} protected override void OnElementChanged(ElementChangedEventArgs e) {base.OnElementChanged(e);if (e.o oldelement != null || Element == null){返回;} //本地容器,将用于实时预览扫描rlMainContainer = new RelativeLayout(上下文);rlMainContainer.SetMinimumHeight (50);rlMainContainer.SetMinimumWidth (100);rlMainContainer。LayoutParameters = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams. layoutparams)MatchParent RelativeLayout.LayoutParams.MatchParent);//将显示最后一个预览帧的本机图像ivPreview = new ImageView(Context); ivPreview.SetMinimumHeight(50); ivPreview.SetMinimumWidth(100); ivPreview.LayoutParameters = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MatchParent, RelativeLayout.LayoutParams.MatchParent); ivPreview.SetScaleType(ImageView.ScaleType.FitCenter); rlMainContainer.AddView(ivPreview); if (Control == null) SetNativeControl(rlMainContainer); MainActivity.instance.setActiveReader(Control, Element); } protected override void Dispose(bool disposing) { if (Element != null) MainActivity.instance.releaseReader(true, Element); base.Dispose(disposing); } } }
稍后我们会解释setActiveReader ()而且releaseReader ()方法从MainActivity类。
MainActivity是应用程序的启动活动。在这里,我们将配置ReaderDevice,连接到设备,监听可用性/连接状态变化,处理收到的结果,请求许可等。
为了侦听可用性和连接状态的变化,并处理请求权限结果,MainActivity继承自IOnConnectionCompletedListener,IReaderDeviceListener而且IOnRequestPermissionsResultCallback.
setActiveReader ()方法有两个输入参数。第一个是RelativeLayout,用于扫描预览,第二个是ScannerPreview元素。
因为我们可以在多个页面中使用扫描仪控制releaseReader ()方法我们释放一些对象,删除事件处理程序,并断开与阅读器设备的连接,以便我们可以从另一个页面访问阅读器设备。
在setActiveReader ()函数在初始化一些变量和设置我们调用的事件处理程序之后initDevice ()函数。
这里取决于我们选择的扫描设备
readerDevice = GetMXDevice(此);if (!listeningForUSB) {readerDevice.StartAvailabilityListening();listeningForUSB = true;}
为MX扫描仪。当设备转动时,MX扫描仪的可用性可以改变在或从,或连接USB线或断开连接,这由IReaderDeviceListener接口。
如果我们要将阅读器设备配置为移动相机我们可以用:
readerDevice = GetPhoneCameraDevice(这个,CameraMode。NoAimer PreviewOption。违约|PreviewOption.HardwareTrigger rlMainContainer);
CameraMode参数为类型CameraMode(定义在CameraMode.java),并接受以下值之一:
PASSIVE_AIMER:初始化阅读器以使用无源瞄准器,无源瞄准器是连接到移动设备或移动设备外壳上的附件,使用移动设备的内置LED闪光灯作为光源,以投射瞄准模式。在这种模式下,设备屏幕上不会显示实时流预览,因为瞄准模式将被投影。
FRONT_CAMERA:初始化阅读器以使用设备的移动前置摄像头(如果可用的话)(并非所有移动设备都有前置摄像头)。这是一种不寻常但可能的结构。大多数前置摄像头没有自动对焦和照明功能,提供的图像分辨率也明显较低。这个选项应该谨慎使用。在这种模式下,照明是不可用的。
以上所有模式都为读者提供以下默认设置:
根据所选择的模式,将设置以下附加选项和行为:
的PreviewOption参数是的类型PreviewOption(定义在PreviewOption.java),并用于更改读取器的默认值或覆盖从选定对象派生的默认值CameraMode.在传递参数时,可以通过OR-ing指定多个选项。可用的选项有:
类型的最后一个参数ViewGroup是我们在渲染器中为相机预览创建的容器。
配置完ReaderDevice我们需要连接到设备上。
在我们建立联系之前ReaderDeviceListener对象的设置是为了接收事件:
readerDevice.SetReaderDeviceListener(这个);
启用从我们使用的读取器发送最后触发的图像:
readerDevice.EnableImage(真正的);
和
readerDevice.EnableImageGraphics(真正的);
我们在图像上标记并显示扫描条形码的结果。
然后我们可以连接:
readerDevice.Connect(这个);
将被调用的事件是:
OnConnectionCompleted(ReaderDevice reader, Throwable error)
方法中的参数抛出错误,如果在尝试连接时出现错误OnConnectionCompleted方法,否则,如果没有发生错误,则error参数将为零.
如果连接成功,则语句读者。ConnectionState == ConnectionState。连接将是真的。
有几个API方法可以更改一些公共属性来配置连接的设备,当ConnectionState是连接。
例如,如果移动相机被用作一个ReaderDevice有默认情况下不启用任何符号.控件中要使用的符号必须启用SetSymbologyEnabledAPI方法:
readerDevice.SetSymbologyEnabled(象征。C128, true, null);readerDevice.SetSymbologyEnabled(象征。数据矩阵,true, null);readerDevice.SetSymbologyEnabled(象征。UpcEan, true, null);readerDevice.SetSymbologyEnabled(象征。Qr, true, null);
您可以直接通过向连接的设备发送命令来完成同样的操作:
readerDevice.DataManSystem。SendCommand(“设置标志。MICROPDF417”);
有了正确配置的读取器,现在就可以扫描条形码了。可以通过调用startScanning方法。ReaderDevice对象。
接下来会发生什么是基于类型ReaderDevice以及它是如何配置的,但总的来说
当满足下列条件之一时,扫描停止:
当条形码被成功解码(第一种情况)时,您将收到一个ReadResults对象中的可迭代结果集合对象ReaderDevice侦听器方法。
public void OnReadResultReceived(ReaderDevice reader, ReadResults results){//防止内存不足异常GC.Collect();//将在Element OnResultReceived中发送的列表,在可移植项目中实现List resList =新列表();//重置上次触发的图像ivPreview.SetImageBitmap(null);//如果您的MX扫描仪配置为多码扫描,您可以从结果中访问所有扫描结果。SubResults//property which is an array that contains ReaderResult objects and it will be null if single code scanning is used. if (results.SubResults != null && results.SubResults.Count > 0) { for (int i = 0; i < results.SubResults.Count; i++) { if (results.SubResults[i].IsGoodRead) { Symbology sym = results.SubResults[i].Symbology; if (sym != null) { resList.Add(new ScannedResult(results.SubResults[i].ReadString, sym.Name, true)); } else { resList.Add(new ScannedResult(results.SubResults[i].ReadString, "UNKNOWN SYMBOLOGY", true)); } } else { resList.Add(new ScannedResult("NO READ", "", false)); } if (results.SubResults[i].Image != null) { ivPreview.SetImageBitmap(renderSvg(results.SubResults[i].ImageGraphics, results.SubResults[i].Image)); } else { if (results.SubResults[i].ImageGraphics != null) { ivPreview.SetImageBitmap(renderSvg(results.SubResults[i].ImageGraphics, ivPreview.Width, ivPreview.Height)); } else ivPreview.SetImageBitmap(null); } } } else if (results.Count > 0) { ReadResult result = results.GetResultAt(0); if (result.IsGoodRead) { Symbology sym = result.Symbology; if (sym != null) { resList.Add(new ScannedResult(result.ReadString, sym.Name, true)); } else { resList.Add(new ScannedResult(result.ReadString, "UNKNOWN SYMBOLOGY", true)); } } else { resList.Add(new ScannedResult("NO READ", "", false)); } if (result.Image != null) { ivPreview.SetImageBitmap(renderSvg(result.ImageGraphics, result.Image)); } else { if (result.ImageGraphics != null) { ivPreview.SetImageBitmap(renderSvg(result.ImageGraphics, ivPreview.Width, ivPreview.Height)); } else ivPreview.SetImageBitmap(null); } } isScanning = false; //Triggering Element OnResultReceived event that is implemented in portable project if (element != null) element.OnResultReceived(resList); }
这里我们重写OnRestart和原事件,所以我们可以断开连接和StopAvailabilityListening当我们最小化时释放所有连接初始化当我们重新启动这个活动时。
OnRestart() {base.OnRestart();//检查我们是否在我们有ScannerPreview元素的页面if (element != null) initDevice();} protected override void OnStop(){//检查readerDevice是否初始化if (readerDevice != null) {readerDevice. stopavailabilitylistening ();listeningForUSB = false;readerDevice.SetReaderDeviceListener(空);readerDevice.Disconnect ();readerDevice = null;} base.OnStop ();}
在这个项目中,我们将设置所有的设置,我们需要ios平台(部署目标,应用程序名称,包标识符..),要求我们需要的权限,添加资产,为ios平台创建自定义渲染器等。
开放Info.plist使用文本编辑器文件并添加以下行:
NSCameraUsageDescription 用于扫描的摄像头 UISupportedExternalAccessoryProtocols com.cognex. comgnex . comgnex . key>NSCameraUsageDescription 。Dmcc com.demo.data . Dmcc com.demo.data
NSCameraUsageDescription关键是相机权限,如果我们想使用MX扫描仪作为阅读器设备与这个应用程序,我们应该添加UISupportedExternalAccessoryProtocols输入信息。这个项目的Plist文件。
接下来将在Assets目录中添加新图标,并创建另一个名为CMBSDKScannerImages并在目录中添加图标
ScannerPreviewRenderer类的自定义呈现器扫描预览(PCL自定义控件)iOS平台。
[assembly: Xamarin.Forms.ExportRenderer(typeof(CMBSDKShoppingCartForms. scannerpreview), typeof(CMBSDKShoppingCartForms. ios . scannerpreviewrenderer))] namespace CMBSDKShoppingCartForms. exportrenderer。iOS{公共类ScannerPreviewRenderer: ViewRenderer{私有UIView容器;private UIImageView ivSVG;private UIImageView ivPreview;protected override void OnElementChanged(ElementChangedEventArgs e) {base.OnElementChanged(e);if (e.o oldelement != null || Element == null){返回;} container = new UIView();//扫描时用于实时预览的原生图像ivPreview = new UIImageView();ivPreview。ContentMode = UIViewContentMode.ScaleToFill;//用于SVG图像的原生图像。 That will be image on which scaned barcode will bi marked and result will be shown ivSVG = new UIImageView(); ivSVG.ContentMode = UIViewContentMode.ScaleToFill; container.AddSubview(ivPreview); container.AddSubview(ivSVG); ivPreview.Frame = new CoreGraphics.CGRect(0, 0, container.Frame.Size.Width, container.Frame.Size.Height); ivPreview.AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth; ivSVG.Frame = new CoreGraphics.CGRect(0, 0, container.Frame.Size.Width, container.Frame.Size.Height); ivSVG.AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth; if (Control == null) SetNativeControl(container); AppDelegate.instance.setActiveReader(Control, Element); } protected override void Dispose(bool disposing) { if (Element != null) AppDelegate.instance.releaseReader(true, Element); base.Dispose(disposing); } } }
稍后我们会解释setActiveReader ()而且releaseReader ()方法从AppDelegate类。
在本课程中,我们将配置ReaderDevice,连接到设备,监听可用性/连接状态变化,处理接收到的结果等。
侦听可用性和连接状态更改AppDelegate类继承ICMBReaderDeviceDelegate接口。
setActiveReader ()方法有两个输入参数。第一个是包含两张图片的UIView原生控件,第二个是ScannerPreview元素。
因为我们可以在多个页面中使用扫描仪控制releaseReader ()方法我们释放一些对象,删除事件处理程序,并断开与阅读器设备的连接,以便我们可以从另一个页面访问阅读器设备。
在setActiveReader ()函数在初始化一些变量和设置我们调用的事件处理程序之后createReaderDevice ()函数。
取决于所选的扫描设备createReaderDevice ()函数。
readerDevice = CMBReaderDevice.ReaderOfMXDevice();
如果我们想用MX扫描仪。当设备打开或关闭,或者USB电缆连接或断开时,MX扫描仪的可用性可能会发生变化,并由ICMBReaderDeviceDelegate接口。我们将此接口设置为阅读器设备的属性
readerDevice。WeakDelegate = this;
让我们听下面三个事件:
ConnectionStateDidChangeOfReader(CMBReaderDevice reader) public void DidReceiveReadResultFromReader(CMBReaderDevice reader, CMBReadResults readResults)
如果我们要将阅读器设备配置为移动相机我们使用
readerDevice = CMBReaderDevice.ReaderOfDeviceCameraWithCameraMode(CDMCameraMode. readerofdevicecamerawithcameramode)NoAimer CDMPreviewOption。违约|CDMPreviewOption.HwTrigger、容器);
的CameraMode参数的类型CDMCameraMode,它接受以下值之一:
以上所有模式都为读者提供以下默认设置:
根据所选择的模式,将设置以下附加选项和行为:
的previewOptions参数(类型)CDMPreviewOption)用于更改读取器的默认值或覆盖从选定对象派生的默认值CameraMode.在传递参数时,可以通过OR-ing指定多个选项。可用的选项如下:
类型的最后一个参数UIView是我们在渲染器中为相机预览创建的容器。
配置后ReaderDevice我们需要连接到设备上。
readerDevice.ConnectWithCompletion((error) => {if (error != null) {new UIAlertView("Failed to connect",错误。Description, null, "OK", null).Show();if (element != null) element. onconnectionstatechanged(“断开”);}});
如果在尝试连接时出现错误,则错误将作为回调函数中的参数抛出。如果一切正常,错误参数将为空。
这个函数将触发ConnectionStateDidChangeOfReader方法。如果连接成功读者。connect state == ConnectionState. connected。
连接成功后,我们可以为ReaderDevice设置一些设置。ReaderDevice设置可以通过已经封装的函数来设置,也可以直接通过向配置的设备发送命令来设置。
例如,如果移动相机被用作阅读器设备有默认情况下不启用任何符号.控件中要使用的符号必须启用SetSymbology包装的功能。
在这个例子中,我们启用了一些符号,并设置设置来获取扫描的最后一帧ivPreview图像和标记条码ivSVG形象.
readerDevice.SetSymbology (CMBSymbology。DataMatrix, true,(错误)=> {if(错误!= null) {System.Diagnostics.Debug。WriteLine(" failed TO ENABLE [DataMatrix], ", error.LocalizedDescription);}});readerDevice.SetSymbology (CMBSymbology。Qr, true,(错误)=> {if(错误!= null) {System.Diagnostics.Debug。WriteLine(" failed TO ENABLE [Qr], ", error.LocalizedDescription);}});readerDevice.SetSymbology (CMBSymbology。C128, true,(错误)=> {if(错误!= null) {System.Diagnostics.Debug。WriteLine(" failed TO ENABLE [C128], ", error.LocalizedDescription);}});readerDevice.SetSymbology (CMBSymbology。UpcEan, true, (error) => { if (error != null) { System.Diagnostics.Debug.WriteLine("FALIED TO ENABLE [UpcEan], ", error.LocalizedDescription); } }); if (element != null && element.ScanningPreviewEnable) { readerDevice.ImageResultEnabled = true; readerDevice.SVGResultEnabled = true; readerDevice.DataManSystem.SendCommand("SET IMAGE.SIZE 0"); }
有了正确配置的读取器,现在就可以扫描条形码了。可以通过调用startScanning方法。ReaderDevice对象。
接下来会发生什么取决于阅读器设备的类型以及它的配置方式,但一般来说:
当满足下列条件之一时,扫描停止:
当条形码被成功解码(第一种情况)时,您将收到一个CMBReadResults中的可迭代结果集合对象ReaderDevice侦听器方法。
public void DidReceiveReadResultFromReader(CMBReaderDevice reader, CMBReadResults readResults) {isScanning = false;//将在Element OnResultReceived中发送的列表,在可移植项目中实现List resList =新列表();//重置上一次触发的图像if (ivPreview != null)Image = null;if (ivSVG != null)Image = null;//如果您的MX扫描仪配置为多码扫描,您可以从结果中访问所有扫描结果。SubReadResults//property which is an array that contains ReaderResult objects and it will be null if single code scanning is used. if (readResults.SubReadResults != null && readResults.SubReadResults.Length > 0) { for (int i = 0; i < readResults.SubReadResults.Length; i++) { if (((CMBReadResult)readResults.SubReadResults[i]).XML != null) { XmlDocument xml = new XmlDocument(); xml.LoadXml(((CMBReadResult)readResults.SubReadResults[i]).XML.ToString(NSStringEncoding.UTF8)); XmlNodeList nll = xml.GetElementsByTagName("status"); if (nll.Item(0).InnerText == "GOOD READ") { byte[] base64result = Convert.FromBase64String(xml.GetElementsByTagName("full_string").Item(0).InnerText); resList.Add(new ScannedResult(System.Text.Encoding.UTF8.GetString(base64result), xml.GetElementsByTagName("symbology").Item(0).InnerText, true)); } else { resList.Add(new ScannedResult("NO READ", " ", false)); } } else { resList.Add(new ScannedResult("NO READ", " ", false)); } if (((CMBReadResult)readResults.SubReadResults[i]).Image != null) { if (ivPreview != null) ivPreview.Image = ((CMBReadResult)readResults.SubReadResults[i]).Image; } if (((CMBReadResult)readResults.SubReadResults[i]).ImageGraphics != null) { if (ivSVG != null) { var parser = new CMBSVG.CDMSVGParser(((CMBReadResult)readResults.SubReadResults[i]).ImageGraphics); var svgData = parser.Parse; var renderer = new CMBSVG.CDMSVGRenderer(svgData); UIImage svgImage = renderer.ImageFromSVGWithSize(((CMBReadResult)readResults.SubReadResults[i]).Image != null ? ((CMBReadResult)readResults.SubReadResults[i]).Image.Size : ivSVG.Frame.Size, new UIImage()); ivSVG.Image = svgImage; } } } } else foreach (CMBReadResult readResult in readResults.ReadResults) { if (readResult.XML != null) { XmlDocument xml = new XmlDocument(); xml.LoadXml(readResult.XML.ToString(NSStringEncoding.UTF8)); XmlNodeList nll = xml.GetElementsByTagName("status"); if (nll.Item(0).InnerText == "GOOD READ") { byte[] base64result = Convert.FromBase64String(xml.GetElementsByTagName("full_string").Item(0).InnerText); resList.Add(new ScannedResult(System.Text.Encoding.UTF8.GetString(base64result), xml.GetElementsByTagName("symbology").Item(0).InnerText, true)); } else { resList.Add(new ScannedResult("NO READ", " ", false)); } } else { resList.Add(new ScannedResult("NO READ", " ", false)); } if (readResult.Image != null) { if (ivPreview != null) ivPreview.Image = readResult.Image; } if (readResult.ImageGraphics != null) { if (ivSVG != null) { var parser = new CMBSVG.CDMSVGParser(readResult.ImageGraphics); var svgData = parser.Parse; var renderer = new CMBSVG.CDMSVGRenderer(svgData); UIImage svgImage = renderer.ImageFromSVGWithSize(readResult.Image != null ? readResult.Image.Size : ivSVG.Frame.Size, new UIImage()); ivSVG.Image = svgImage; } } } //Triggering Element OnResultReceived event that is implemented in portable project if (element != null) element.OnResultReceived(resList); }
可能会出现由于电池电量不足或手动断开电缆而导致设备断开的情况。这些情况可以通过ConnectionStateDidChangeOfReader的回调ICMBReaderDeviceDelegate.
注意:的AvailabilityDidChangeOfReader方法也会在设备物理不可用时调用。这意味着(重新)连接是不可能的。属性的可用性属性ReaderDevice对象调用ConnectWithCompletion方法。
如果您计划使用cmbSDK使用智能手机或平板电脑(没有MX移动终端)进行移动扫描,SDK需要安装许可密钥。没有许可密钥,SDK仍将运行,尽管扫描结果将被模糊化(SDK将随机地将扫描结果中的字符替换为星号字符)。
请与您的康耐视销售代表联系,了解如何获取许可证密钥,包括可用于30天评估SDK的试用许可证。
获得许可密钥后,有两种方法可以在应用程序中添加许可密钥。
为Android平台打开清单文件并在应用程序标记中添加此元标记
或者您可以在连接之前直接从MainActivity中的代码中注册sdk
private void initDevice(){…ReaderDevice.SetCameraRegistrationKey(“YOUR_MX_MOBILE_LICENSE”);readerDevice.Connect(这个);…}
为iOS平台开放Info.plistfile and add this key
MX_MOBILE_LICENSE 您的license密钥 . key>MX_MOBILE_LICENSE
或者你可以在连接之前直接从AppDelegate中的代码注册你的sdk
private void createReaderDevice(){…CMBReaderDevice。SetCameraRegistrationKey(“您的许可密钥”);connectToReaderDevice ();…}