作为一位 .NET 技术的死忠,开发 iOS 应用当然要使用 Xamarin 啦!
本文用我的阅读的文档和实践为素材,介绍如何使用 Xamarin 开发一个 iOS 的键盘扩展。
本文不会花篇幅来讲如何搭建 Xamarin iOS 开发的环境,不然这篇文章就没有重点。
于是,请阅读这一篇来了解如何搭建 Xamarin iOS 的开发环境:
了解以下背景知识,有助于我们接下来开发的时候少踩一些坑。当然我不会在这里说 iOS 应用开发的所有背景知识,只会说与 iOS 键盘扩展相关的部分。
这个不用太在意里面的实现,因为它只是我们的“容器项目”(前面有介绍)。实际上在本文我们完全不会碰这个项目里面的代码,只是为了配置我们的 iOS 应用包而已。未来你可以在这个容器应用里面做键盘的个性化设置。
然后,选择 iOS 平台。
我们只需要 iOS 端。因为对于键盘,不同系统的实现差异很大,之间共享的代码只能是非键盘部分的代码了。
当你创建完之后,你会看到三个不同的项目。
你可能发现 Walterlv.KeyboardExtension.Keyboard 项目有些奇怪,里面有 Main 函数和 AppDelegate,按道理这是一个主程序包。然而实际测试中单独有这个项目是跑不起来的(这可能是一个 Bug,如果修复了,请在下面评论或者邮件告知我,谢谢了)。
于是,Main 和 AppDelegate 这两个文件是可以删除的。如果你强迫症,就删掉吧。当然不删掉也不影响,不过我删掉了。
在 iOS 容器应用上面添加键盘扩展项目作为引用。
如果你感兴趣去查看 Walterlv.KeyboardExtension.iOS 项目中对 Walterlv.KeyboardExtension.Keyboard 项目的引用节点的话,你会发现 Xamarin 已经自动为这个项目标记上了 <IsAppExtension />
。只有加上了 AppExtension 标记,Xamarin 才会把这个项目作为 iOS 扩展项目进行打包。
<ProjectReference Include="..\..\Walterlv.KeyboardExtension.Keyboard\Walterlv.KeyboardExtension.Keyboard.csproj">
<Project>{d6f006e7-3c98-4b97-b2d5-4d2e3bc2f945}</Project>
<Name>Walterlv.KeyboardExtension.Keyboard</Name>
<IsAppExtension>true</IsAppExtension>
<IsWatchApp>false</IsWatchApp>
</ProjectReference>
在以上三个步骤完成之后,理论上你是可以正常编译此项目的。
配置包信息
iOS 应用的包信息存储在 plist 中。所以在这一节,你需要正确配置两个项目的 plist。
没错!是两个项目。还记得前面背景知识里面我们说到容器项目和扩展项目就是两个不同的应用吗?
配置 plist 的方法,就是在 Visual Studio 里面双击这个文件。
按照下图这样配置:
说明:
至此,你的项目可以直接编译了。如果你有真机部署环境,都可以直接部署到真机上看效果了。
本文不会花篇幅来讲如何真机部署调试,不然这篇文章就没有重点。
但是你可以阅读:使用 Xamarin 在 iOS 真机上部署应用进行调试
当然这是 Mac 版本的(毕竟我在 Windows 上实际也没有成功真机调试过,我是 git 同步到 Mac 上用 Visual Studio for Mac 来真机调试的)。
只是你需要注意做这些内容:
下面是我部署到真机上之后,在亮暗两种不同的界面下的键盘截图(就是上面的项目,没有改任何代码):
我们把 Walterlv.CloudKeyboard.iOS.Extension 也就是那个键盘扩展项目删除得只剩下 KeyboardViewController.cs 了,我们也只需要在这个类中写代码而已。
要控制文字输入,就是使用 TextDocumentProxy
实例。我们的 KeyboardViewController
继承自 UIInputViewController
,于是我们能够在类中直接使用 TextDocumentProxy
实例。
在光标处插入文字:
TextDocumentProxy.InsertText("walterlv");
如果要插入换行或者确认输入,则使用:
TextDocumentProxy.InsertText("\n");
在光标处删除前一个字:
TextDocumentProxy.DeleteBackward();
如果想要清空文本,则可以循环删除:
while (TextDocumentProxy.HasText)
{
TextDocumentProxy.DeleteBackward();
}
你没有办法删除后一个字,也不能获取到用户输入的任何内容。
关于换行,特别注意:如果文本框被设置为发送或者其他非换行的功能,那么使用 InsertText
单独插入换行时才能正常执行这些功能。如果调用此代码之前还有其他的插入文字,那么最终就只会是换行,而不会执行其他的功能。实际上我在这一点上踩了坑,导致在 QQ 或者其他工具中只能实现换行,而无法发送消息。
iOS 的键盘有不同种类的确认,需要键盘针对 TextDocumentProxy.
我还没有找到办法直接完成文本的输入,例如执行确认按钮的逻辑。而确认按钮有这么些不同的情况:
// 我当然是写 C# 语言版本的枚举,而不是 Object-C 版本的啦。
public enum UIReturnKeyType : long
{
Default,
Go,
Google,
Join,
Next,
Route,
Search,
Send,
Yahoo,
Done,
EmergencyCall,
Continue,
}
纯本地的键盘很难在打字速度上获得优势,各种主流的输入法也通常借助网络来提高自身的输入准确度。
用户需要在键盘设置里面开启键盘的“允许完全访问”才能让对应的输入法获得网络访问的权限。如果用户没有给权限,那么网络访问的时候键盘扩展就会出现异常,然后闪退。
然而如果你去我们刚刚开发的输入法中看,你会发现我们的输入法没有提供这样的选项可以设置。那么如何能够添加这个设置以便进行网络访问呢?
方法是修改键盘扩展项目的 Info.plist 文件。这个时候的修改,我们就不能使用 Visual Studio 中自带的 plist 编辑器了,我们需要使用文本编辑器来编辑 plist 文件。
在你的 Info.plist 文件中找到 RequestsOpenAccess
属性,然后将它分值从 false
改为 true
:
<key>RequestsOpenAccess</key>
-- <false/>
++ <true/>
这个属性设为 true
之后,再次部署,你将可以在你的键盘设置里面看到“允许完全访问”的设置项。开启之后,你就能在你的键盘里面访问网络了。
一般来说你不用阅读这一小节的内容。因为现在基本上各种服务都已经是 https 了,http 基本已经绝迹。但是如果你需要临时部署一个服务,没来得及申请 https 证书的话,那么就需要使用本小结的内容让你的键盘支持 http 的访问。
继续打开你的键盘扩展项目的 Info.plist 文件,在根字典的最后添加一个完整的字典属性 NSAppTransportSecurity
:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>walterlv.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
特别注意,里面的 walterlv.com
需要换成你自己的域名。是域名,不用包含端口号。
这样,你就能在键盘中访问 http://walterlv.com 了。
如果你还遇到了一些其他诡异的问题:
参考资料
[iOS 8 Custom Keyboard Tutorial: How to Create A Third-Party Keyboard Extension | iPhone and iOS App UI Design Templates](http://www.appdesignvault.com/ios-8-custom-keyboard-extension/#a_aid=mdev) |
---|
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com) 。