Usabilla for Apps - iOS SDK
Usabilla for Apps 允许您轻松灵活地从用户收集反馈。
在 Usabilla SDK 版本 6.4 中,除了截图能力以外,新增了两个新功能
- 使用相机捕获图像
- 使用绘图工具在图像上绘制注释
- 关于相机,iPad 支持所有方向,而 iPhone 只支持纵向模式。
- 竖屏模式的 iPhone 不支持这些功能,但可以捕获使用图库中的图像。
需求
- iOS 9.0+
- Xcode 10+
- Swift 4.0+
安装
您可以使用 Cocoapods、Carthage 或手动方式安装 Usabilla SDK。
此版本基于 Xcode 11.3.1 开发,并采用了模块格式稳定性(自 6.4.3 版本起)。它在 Xcode 11 及以上版本中应该可以编译和运行。早期版本可在我们的 git 仓库找到。有关 Carthage 的信息,请参阅 Carthage 部分。
CocoaPods
Usabilla SDK 可在 CocoaPods 上找到。您可以通过以下方式安装 CocoaPods:
$ gem install cocoapods
若要在项目中使用 SDK,请在您的 Podfile
中指定它
use_frameworks!
target 'YourProjectTarget' do
pod 'Usabilla', '~> 6.4.7'
End
然后,运行以下命令:
$ pod install
Carthage
Usabilla SDK 也可以通过 Carthage 获取。
按照 这些说明 将 Carthage 添加到项目中。
然后,将以下行添加到您的 Cartfile
binary "https://raw.githubusercontent.com/usabilla/usabilla-u4a-ios-swift-sdk/master/Usabilla.json"
master 分支的发布版本是为 Xcode 11.3.1 构建的。
对于其他 Xcode 版本,使用:
binary "https://raw.githubusercontent.com/usabilla/usabilla-u4a-ios-swift-sdk/Xcode-11.4.1/Usabilla.json"
将 Xcode-11.4.1 替换为所需的版本,例如 Xcode-10
手动
您可以下载仓库的最新版本,并将 Usabilla.framework 添加到应用的嵌入式框架中。
在将应用提交到 App Store 的过程中,您可能会遇到问题。这是由于 App Store 自身的一个bug引起的。
您可以通过在应用的目标的 构建阶段 中的 嵌入框架 阶段之后创建一个新的 运行脚本阶段,并复制此处可用的脚本(见此链接)来解决这个问题。
初始化
我们建议在AppDelegate中进行SDK初始化。然而这并非强制要求,初始化也可以在其他地方进行而不会出现任何问题。
请将Usabilla SDK导入到您的AppDelegate中。
import Usabilla
在didFinishLaunchingWithOptions中添加以下行
Usabilla.initialize(appID: "appID")
您也可以通过调用以下方法在SDK初始化完成后运行回调
Usabilla.initialize(appID: "appID") {
// Your callback code here
}
initialize方法将负责
- 提交任何挂起的反馈项。
- 获取并更新与应用程序ID关联的所有活动。
- 初始化SDK的一些后台进程。
⚠️ 如果没有调用此方法,将阻止SDK运行。所有功能将无法使用。
调试模式
为了在开发期间从SDK中获得更多见解,您可以通过以下方式启用日志记录
Usabilla.debugEnabled = true
默认情况下,此属性设置为false
。
活动
Usabilla for Apps SDK的第4版引入了新的活动功能。本指南介绍了活动功能及其所有必要的步骤。
在Usabilla for Apps平台中,活动定义为针对特定用户群体的主动调查。
能够在移动应用中运行活动很棒,因为它允许您从目标用户那里收集更多特定见解。更好的是,创建新活动和管理现有活动无需发布新版本的应用。一切都可以从Usabilla网络界面管理。
您可以运行任意数量的活动并将它们设置为目标用户组在满足特定目标选项时触发。向用户显示活动的配置方式将与现有Usabilla客户熟悉。您可以按需配置,就像您习惯于使用被动反馈表单一样。
运行移动活动的最重要的方面是“事件”。事件是在SDK中配置的自定义触发器。当发生预定义的事件时,它允许您触发活动。用户在您的应用中成功购买就是一个很好的事件例子。
应用程序ID
应用程序ID是一个标识符,用于将活动与应用程序关联。通过使用特定的应用程序ID加载SDK,它将检索与给定应用程序ID关联的所有活动。
您可以将活动针对多个应用程序进行定位(例如,iOS生产应用程序,iOS测试版应用程序)通过将其与多个应用ID关联。
目标选项
活动由事件触发的。事件用于在您的应用中发生某些事情时与SDK进行通信。因此,SDK将根据Usabilla网页界面的配置对事件做出反应。要向SDK发送事件,请使用
Usabilla.sendEvent(event: String)
有多种选项可以定义更具体的活动目标规则
- 您可以设置事件必须发生的次数(例如,3次)。
- 指定要触发的活动应触发的用户百分比(例如,10%)。
- 定义您是否想针对特定设备语言。
您还可以使用自定义变量来细分用户基础。自定义变量可以用于指定用户的某些特性,并将活动仅针对特定的子集进行目标。
有关如何使用自定义变量的更多信息,请参阅自定义变量
注意:活动将永远不会为同一用户触发多次。
活动切换
Usabilla SDK允许您确保不在不合适的时候触发活动。例如,当您的应用用户正在进行敏感流程时,不应该被打扰。这可以通过设置布尔属性canDisplayCampaigns
来实现,以满足您的需求。
Usabilla.canDisplayCampaigns = false
将其设置为true
将允许SDK在触发时显示任何活动。将其设置为false
将阻止显示所有活动。
即使canDisplayCampaigns
设置为false
,SDK也继续接收所有事件。如果活动发生,它将不会显示或延迟:该事件实例将丢失。
默认情况下,canDisplayCampaigns
设置为true
。
如果您的某个或多个活动在将canDisplayCampaigns
属性设置为false
时触发,然后在稍后更改为其true
,SDK将不会显示该活动。这是因为在稍后的时间,此时可能不相关显示该活动给用户。
活动提交回调
通过实现
func campaignDidClose(withFeedbackResult result: FeedbackResult, isRedirectToAppStoreEnabled: Bool) {}
与被动反馈方法不同,活动方法只返回一个FeedbackResult,并且只调用一次。
重置所有活动
在开发和测试过程中,重置您活动的状态并重新显示它们可能会有帮助。
您可以通过调用 Usabilla.resetCampaignData(completion: nil)
来完成此操作。
您可以在 SDK 完成重置活动数据后执行一个闭包。
此方法将与 Usabilla 服务器同步您的数据,因此它将获取所有新的活动,并删除未激活的活动。
管理现有活动
您可以在创建新活动的 Usabilla for Apps 活动编辑器 中立即开始收集活动结果。默认情况下,新活动被标记为未激活。在 Usabilla for Apps 活动概览 页面上,您可以随时激活或停用现有活动以满足您的特定需求。
此外,您还可以随时更新活动的丰富内容(例如问题)。请注意,您对现有活动所做的更改可能会影响您收集数据的一致性(更改前后不同的回复)。
此外,您还可以更改活动的定位选项。请注意,更新活动定位选项将重置用户设备上之前所做的任何进度。
活动结果
汇总活动结果可以下载自 活动概览。在这里,您可以为每个活动下载结果,格式为 CSV。
活动结果将包含用户提供的答案。活动的回复将被逐页收集并发送到 Usabilla 页面。这意味着即使用户在活动中途决定放弃,您也会收集到有价值的见解。当用户继续到下一页时,上一页的结果将提交给 Usabilla。除了显示您活动问题答案的活动结果外,您还可以查看设备元数据和自定义变量。
至于活动结果,请注意,编辑现有活动的表单将影响汇总活动结果。
- 向表单添加新问题将向 CSV 文件添加额外的列。
- 从现有表单中删除问题不会影响之前收集的结果。关联的列及其数据仍将在 CSV 文件中。
- 将问题类型替换为不同的题目也是可能的。当你在 Usabilla for Apps 营销编辑器中给出相同的 'name' 时,结果将显示在同一列。
被动反馈
被动反馈是不由事件触发的一种反馈表单。它们大多(但不一定)由用户启动。
加载表单
SDK 使用您从 Usabilla 创建新表单后获得的 Form ID 来获取并在您的应用程序内部显示表单。
SDK 的基本实现如下
class SomeViewController: UIViewController, UsabillaDelegate {
override func viewDidLoad() {
super.viewDidLoad()
Usabilla.delegate = self
Usabilla.loadFeedbackForm("Form ID")
}
//Called when your form successfully load
func formDidLoad(form: UINavigationController) {
present(form, animated: true, completion: nil)
}
//Called when your forms can not be loaded. Returns a default form
func formDidFailLoading(error: UBError) {
//...
}
}
预加载表单
如果您知道用户将在离线时需要显示反馈表单,您可以预先加载和缓存它,使其在任何给定时刻可用。
使用以下方法预加载表单
UsabillaFeedbackForm.preloadFeedbackForms(withFormIDs: ["FORM_ID_1", "FORM_ID_2"])
这将获取表单的最新版本并将其缓存到 SDK 中。
当您请求该表单时,如果没有网络连接,SDK 将使用缓存版本,用户将能够提交反馈。
离线期间提交的反馈将在连接恢复时发送。
如果需要,您可以使用以下方法清空缓存
UsabillaFeedbackForm.removeCachedForms()
iPad 显示
在 iPad 上,被动反馈表单的呈现风格默认设置为 formSheet。如果您想覆盖此行为并实现全屏显示,可以使用以下方法做到这一点。
func formDidLoad(form: UINavigationController) {
form.modalPresentationStyle = .fullScreen
present(form, animated: true, completion: nil)
}
添加截图
可以将截图附加到反馈表单中。
您可以在任何时刻调用截图功能进行屏幕截图。
let image = Usabilla.takeScreenshot(self.view)
要将截图附加到表单中,请在调用时将其作为参数传递。
Usabilla.loadFeedbackForm("Form Id", screenshot: image)
如果您不想对当前视图进行屏幕截图,将 nil
传递给 screen
参数。
自定义屏幕截图和敏感信息
除了使用 Usabilla.takeScreenshot()
方法进行屏幕截图外,您还可以在调用 Usabilla.loadFeedbackForm()
时通过传递 image
参数来提供任何您希望的图像。
这将允许您通过例如自己进行截图、删除所有不需要的信息并提交审查过的版本等方式,隐藏任何用户的敏感信息。
反馈提交回调
通过实现
func formDidClose(formID: String, withFeedbackResults results: [FeedbackResult], isRedirectToAppStoreEnabled: Bool) {
//...
}
此代理方法提供一个数组 FeedbackResult
,因为用户可能会多次提交表单,并且此方法只为所有发送的反馈调用一次。
FeedbackResult
struct FeedbackResult {
let rating: Int?
let abandonedPageIndex: Int?
var sent: Bool
}
当用户与 评分 互动时,评分 值会立即设置,即使表单未提交,也会报告。
只有当用户在提交前取消表单时,才会设置 abandonedPageIndex。
示例
func formDidClose(formID: String, with feedbackResults: [FeedbackResult], isRedirectToAppStoreEnabled: Bool) {
guard let feedback = feedbackResults.first else {
return
}
if feedback.sent == false {
let abandonedPageIndex = feedback.abandonedPageIndex
print("Hey why did you left the form here \(abandonedPageIndex)")
return
}
if let rating = feedback.rating {
if rating >= 4 && isRedirectToAppStoreEnabled {
// Prompt the user for rating and review
}
}
}
处理手动关闭
您可以自定义表单关闭的方式,可以通过添加以下行来实现:
Usabilla.dismissAutomatically = false
并实现 formWillClose 代理方法
func formWillClose(form: UINavigationController, formID: String, withFeedbackResults results: [FeedbackResult], isRedirectToAppStoreEnabled: Bool) {
// handle your custom dismiss e.g: dismiss(animated: true, completion: nil)
}
警告:这样做后,表单将不会自行关闭,您将对其正确行为承担唯一责任。此外,代理方法 formDidClose
也不会被调用。
遮蔽私人可识别信息
SDK 具有各种选项,可以在后端对输入文本数据(特别是 文本输入
和 文本区域
)进行遮挡。请注意,电子邮件输入字段不是可以被遮挡的。
它将匹配一组正则表达式并将其替换为默认的字符 "X"。
SDK 有一个 setDataMasking
方法可以用作如下:
Usabilla.setDataMasking()
Usabilla.setDataMasking(masks: [String])
Usabilla.setDataMasking(masks: [String], maskCharacter: Character)
masks
是一个用于在输入字段中隐藏数据的正则表达式列表。它使用SDK提供的默认正则表达式。maskCharacter
是一个替换匹配的正则表达式的字符。默认情况下,它使用“X”。
SDK提供的默认正则表达式包括:电子邮件地址和数字
对于电子邮件,它使用
[a-zA-Z0-9\+\.\_\%\-\+]{1,256}\@[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}(\.[a-zA-Z0-9][a-zA-Z0-9\-]{0,25})+
对于长度至少为4的数字
[0-9]{4,}
可以通过以下方式访问默认正则表达式
Usabilla.defaultDataMasks
自定义变量
您可以传递自定义变量,这些变量将附加到用户发送的反馈中。自定义变量存储在SDK公共接口中的名为customVariables
的字典对象中。
您可以通过公共方法设置自定义变量
Usabilla.setCustomVariable(value: Any?, forKey: String)
或通过简单地修改字典对象
Usabilla.customVariables["key"] = "value"
由于SDK使用JSONSerialization将自定义变量转换为JSON,因此需要考虑其限制。自定义变量的value
必须是NSString、NSNumber、NSArray、NSDictionary或NSNull的实例。
尝试将无效的对象设置为自定义变量将导致该对象不被设置,并在控制台打印错误。
您可以通过调用JSONSerialization.isValidJSONObject(object)
始终检查对象是否被认为是有效的。
自定义变量将作为随每个反馈项发送的额外反馈数据添加,无论来自被动反馈还是活动。
只要value
是字符串,自定义变量就可以用作定向选项。
App Store评分
要决定是否提示用户进行评分,您可以读取Submission callback
或Campaign submission callback
传递的用户活动的信息。
在Usabilla网页界面中,您可以定义是否应提示特定反馈表单进行评分。
通过编程删除表单或活动
SDK提供了一种方法,通过以下方法编程地丢弃所有表单
let result = Usabilla.dismiss()
这将导致删除表单或活动。不会调用任何代理方法,例如formDidClose
。
如果存在表单或活动,该方法将返回true,否则返回false。
强制指定界面方向
可以强制使活动或表单以特定方向显示,无论设备方向或应用程序支持的界面方向如何。
Usabilla.orientation = .landscapeLeft
在显示活动或表单之前设置此属性。默认值为
Usabilla.orientation = .all
应该也用于重置属性,以遵循应用程序支持的界面设置。
UI 定制
自定义表情符号评分
可以使用自定义图片代替 SDK 中提供的原生图片。
要这样做,您必须提供一组(或两组,具体取决于您想实现什么)五个 UIImage
图片,这些图片将用作 Usabilla 的默认表情符号。数组的第一个元素应该是最低或最左侧的项目,而第 5 个元素应该是最高或最右侧的。目前,SDK 不会检查列表是否有效。
仅提供所选版本
您可以提供一个仅包含所选图标版本的列表。
当选中时,图片将显示为 0.5 的透明度,未选中时为 1 的透明度。
let a = UIImage(named: "1")!
let b = UIImage(named: "2")!
let c = UIImage(named: "3")!
let d = UIImage(named: "4")!
let e = UIImage(named: "5")!
Usabilla.theme.images.enabledEmoticons = [a, b, c, d, e]
提供选中未选两版都提供
您可以提供两个包含选中版本和未选版本图标的列表。
图标将根据其状态从一个列表中选择。
let enabled = createEnabledArray()
let disabled = createDisabledArray()
Usabilla.theme.images.enabledEmoticons = enabled
Usabilla.theme.images.disabledEmoticons = disabled
自定义星级评分
您可以通过在UsabillaTheme中设置star
和starOutline
来更改星级评分的样式。
请注意,要在您的表单中显示星级评分,您必须首先在Usabilla Web界面中启用它。
Usabilla.theme.images.star = UIImage(named: "starFilled")!
Usabilla.theme.images.starOutline = UIImage(named: "starOutline")!
自定义字体
您可以通过设置UsabillaTheme.fonts
结构的regular
和bold
属性来更改反馈表单的字体。如果没有设置,SDK将使用默认的系统字体。
Usabilla.theme.fonts.regular = UIFont(name: "Helvetica-LightOblique", size: 20)
Usabilla.theme.fonts.bold = UIFont(name: "Helvetica-Bold", size: 20)
自定义颜色
所有颜色均来自Usabilla网站,而非SDK。您可以在我们的知识库中找到颜色的详细说明和作用。
唯一的例外是用于更改导航栏颜色的header
颜色。
您可以在显示表单之前通过调用Usabilla.theme.colors.header = UIColor.red
来设置头部颜色。
本地化
对于网站界面不可定制的所有文本,您可以在应用程序中提供自己的翻译,使用应用内的.string
本地化文件。
此文件还包括在启用VoiceOver时读取的所有可访问性标签。
String文件内容
如果您想提供自己的翻译,您需要覆盖默认.string文件中的所有键。
带有键和默认文本的默认文件如下
///Default usabilla english localization
"usa_form_continue_button" = "Next";
"usa_form_close_button" = "Close";
"usa_form_required_field_error" = "Please check this field";
"usa_screenshot_placeholder" = "Add screenshot";
// Accessibility labels
"usa_mood_select_a_rating_out_of" = "select a rating out of";
"usa_accessibility_field_required" = "This field is required";
"usa_choose_from_options" = "Choose from %d options";
"usa_delete_screenshot" = "delete screenshot";
"usa_edit_screenshot" = "change screenshot";
"usa_powered_by_usabilla" = "powered by usabilla";
"usa_tap_to_visit_usabilla" = "tap to visit usabilla.com";
"usa_accessibility_button_label_continue" = "Continue";
// Emoticons
"usa_mood_hate" = "Hate";
"usa_mood_dislike" = "Dislike";
"usa_mood_neutral" = "Neutral";
"usa_mood_like" = "Like";
"usa_mood_love" = "Love";
// Stars
"usa_mood_one_star" = "1 star";
"usa_mood_two_star" = "2 stars";
"usa_mood_three_star" = "3 stars";
"usa_mood_four_star" = "4 stars";
"usa_mood_five_star" = "5 stars";
// checkbox & radio button
"usa_multiple_options_possible" = "Multiple options possible";
"usa_one_option_possible" = "One option possible";
"usa_selected" = "selected";
"usa_unselected" = "unselected";
// Added in SDK Version 6.4.0
//camera button
"usa_camera_navbar_left_button" = "Cancel";
// Screenshot anotation
"usa_retake_button_title" = "Retake";
"usa_back_button_title" = "Back";
"usa_add_button_title" = "Add";
"usa_done_button_title" = "Done";
"usa_back_button_library_title" = "Library";
"usa_library_title" = "Library";
"usa_edit_title" = "Edit";
"usa_add_title" = "Add photo";
"usa_camera_error_title" = "No access to camera";
"usa_camera_error_description" = "Allowing access lets you take photos to add to your feedback.";
"usa_camera_settings_title" = "Allow access to camera";
"usa_library_error_title" = "No access to library";
"usa_library_error_description" = "Allowing access lets you select a photo to add to your feedback.";
"usa_library_settings_title" = "Allow access to library";
如果没有覆盖键,则显示的是键本身而不是文本。
如果您想使用自定义.string文件,可以通过以下方式实现
Usabilla.localizedStringFile = "your_localization_file_name"
提供文件名,不包括.string扩展名。
权限
如果用户尝试设置自定义截图,SDK将请求访问图库的权限。
我们现在也请求访问相机。
这些隐私权限需要在主应用上
NSCameraUsageDescription
NSPhotoLibraryUsageDescription
请确保为这些属性中的每一个都提供了描述字符串
请参阅Apples的技术文档,了解如何本地化这些内容。
注意:如果在表的高级设置面板中未启用“显示截图”选项,则相机和相册库将不会显示。但是,由于您的应用(包含此SDK)具有可能使用它们的特性,必须包含这些隐私权限以通过App商店审查。在这种情况下,它们将永远不会显示给您的最终用户。
与Obj-C应用的集成
要将SDK集成到您的Obj-C应用中,请遵循Apple官方指南,了解如何在同一项目中使用Swift和Objective-C。
一种快速解决这个问题的方式是创建一个Swift文件,您将在其中处理您的应用。在创建新文件并设置好Bridge Head之后,您可以在Swift类中扩展现有的视图控制器,以无缝集成SDK到您的应用中。
在这个示例中,您可以看到Obj-C中的ViewController
#import "ViewController.h"
//Remember to import the auto-generated Swift header, otherwise, you won't see your Swift extension
#import "objctest-Swift.h"
@interface ViewController ()
@end
@implementation ViewController
- (IBAction)buttonPressed:(id)sender {
[self showForm];
}
@end
及其Swift扩展,实现SDK
import Usabilla
extension ViewController : UsabillaDelegate {
override open func viewDidLoad() {
super.viewDidLoad()
Usabilla.delegate = self
}
func formDidLoad(form: UINavigationController) {
present(form, animated: true)
}
func formDidFailLoading(error: UBError) {
//...
}
@objc public func showForm() {
Usabilla.loadFeedbackForm("Form ID")
}
}