最近开始慢慢接手项目,遇到剪切板功能相关使用的问题,一直存在各种问题,于是做了一些深入的研究,在此记录一下。
需求:类似于淘口令的应用,但是要求不能更改剪切板的内容,在自己的应用内只能检测一次,再者如果是自己应用内的淘口令,自己不能检测。
分析
面对这样的需求,显而易见就是使用系统剪切板的功能UIPasteboard *systemBoard = [UIPasteboard generalPasteboard];
,因为只有系统剪切板才能完成不同应用之间的数据共享。其次就是要准确识别剪切板的内容是自己的应用保存的还是别人的应用保存的,这个就比较难了,网上应该还没有相关的方案,在自己摸索下,终于有了比较成熟的方案,下面会有相关的代码。
UIPasteboard简单使用
UIPasteboard
有很多中用法,在此主要说说保存字符串,其它数据类型,请参考提供的相关文章。
//创建系统剪切板
UIPasteboard *systemBoard = [UIPasteboard generalPasteboard];
//将文本写入剪切板
systemBoard.string = content;
//读取剪切板的内容
NSString *content = systemBoard.string;
详细参考:ios开发 UIPasteboard 的简单使用,UIPasteboard粘贴板(iOS) 看这篇就够了
UIPasteboard的高级接口
下面提到的这些接口和属性,对准确识别剪切板的内容有着至关重要的作用,请耐心看完。
//数据组数
@property(readonly,nonatomic) NSInteger numberOfItems;
//所有数据对象
@property(nonatomic,copy) NSArray *items;
//添加一组数据对象
- (void)addItems:(NSArray<NSDictionary<NSString *, id> *> *)items;
UIPasteboard数据打标签
通过学习和实验发现,UIPasteboard
常用的接口都是存在类型pasteboardType
覆盖的,但是也有类型不覆盖的接口,就比如今天要将的addItems
接口。
//创建系统剪切板
UIPasteboard *systemBoard = [UIPasteboard generalPasteboard];
//将文本写入剪切板
systemBoard.string = content;
//给剪切板加入一条标记性的数据,只是为了检测剪切板的数据是否来自当前应用
NSDictionary<NSString *, id> *item = @{PASTEBOARD_MARK:content};
[systemBoard addItems:@[item]];
每次应用存入剪切板的数据都附加的再加一条标记数据,作为读取剪切板的时候的判断标志。
有人可能会问:为什么这样可以呢?
哈哈,因为不管是那个应用,主要对系统剪切板进行写操作了,都会重置items
数据。这样也就说明只有我们自己写入的数据才有特定的标志,别人再写入就会覆盖我们的数据,如此就可以准确识别数据是不是我们自己写入的数据了。
UIPasteboard数据过滤
我们的目标是只处理别人写入剪切板的数据,所以要对自己写入的数据进行过滤。
+ (BOOL)hasMark{
//创建系统剪切板
UIPasteboard *systemBoard = [UIPasteboard generalPasteboard];
if(!systemBoard.numberOfItems) {
return YES;
}
NSArray<NSDictionary<NSString *, id> *> *items = systemBoard.items;
long count = systemBoard.numberOfItems;
for(int i=0; i < count; i++){
NSDictionary<NSString *, id> *item = [items objectAtIndex:i];
if([[item allKeys] containsObject:PASTEBOARD_MARK]){
return YES;
}
}
return NO;
}
hasMark
方法是用来判断剪切板是否有我们写入的标志数据,返回YES表示此条剪切板数据是我们自己写入的,则不需要处理。否则就是别人的数据,需要处理的。
总结
完整代码如下:
PasteboardUtils.h
剪切板操作工具类头文件
#import <Foundation/Foundation.h>
//剪切板使用的工具类,主要处理应用内剪切板指只读区一次的问题
@interface PasteboardUtils : NSObject
//读取剪切板,nil表示剪切板为空
+ (NSString *) read;
//保存到剪切板
+ (void) save : (NSString *) content;
//清空剪切板
+ (void) clear;
@end
PasteboardUtils.m
剪切板操作工具类实现
#import "PasteboardUtils.h"
#import "OptsUtils.h"
#define PASTEBOARD_MARK @"定义你自己的标记"
//读取剪切板的内容只从系统剪切板读区
//应用内保存到剪切板的内容在主动读取的时候需要过滤掉
@implementation PasteboardUtils
+ (NSString *)read {
//创建系统剪切板
UIPasteboard *systemBoard = [UIPasteboard generalPasteboard];
if(!systemBoard.numberOfItems) {
//剪切板为空
return nil;
}
if([self hasMark]) {
//剪切板数据已经标记过了,则数据来自当前应用,不予处理
return nil;
}
return systemBoard.string;
}
+ (void)save:(NSString *)content {
//创建系统剪切板
UIPasteboard *systemBoard = [UIPasteboard generalPasteboard];
//将文本写入剪切板
systemBoard.string = content;
//给剪切板加入一条标记性的数据,只是为了检测剪切板的数据是否来自当前应用
NSDictionary<NSString *, id> *item = @{PASTEBOARD_MARK:content};
[systemBoard addItems:@[item]];
}
+ (void)clear {
//创建系统剪切板
UIPasteboard *systemBoard = [UIPasteboard generalPasteboard];
systemBoard.string = @"";
}
+ (BOOL)hasMark{
//创建系统剪切板
UIPasteboard *systemBoard = [UIPasteboard generalPasteboard];
if(!systemBoard.numberOfItems) {
return YES;
}
NSArray<NSDictionary<NSString *, id> *> *items = systemBoard.items;
long count = systemBoard.numberOfItems;
for(int i=0; i < count; i++){
NSDictionary<NSString *, id> *item = [items objectAtIndex:i];
if([[item allKeys] containsObject:PASTEBOARD_MARK]){
return YES;
}
}
return NO;
}
@end
OptsUtils.h
条件判断工具类头文件
#import <Foundation/Foundation.h>
@interface OptsUtils : NSObject
//判断字符串是否为空串
+(BOOL) isEmptyString : (NSString *) string;
//判断两个字符串是否相等
+(BOOL) isEqualToString : (NSString *) stringA : (NSString *) stringB;
@end
OptsUtils.m
条件判断工具类实现
#import "OptsUtils.h"
@implementation OptsUtils
+ (BOOL)isEmptyString : (NSString *) string {
if(!string) {
return YES;
}
if([string isKindOfClass:[NSNull class]]){
return YES;
}
if(!string.length){
return YES;
}
return NO;
}
+ (BOOL)isEqualToString:(NSString *)stringA :(NSString *)stringB {
if([self isEmptyString:stringA] && [self isEmptyString:stringB]) {
return YES;
}
if([self isEmptyString:stringA]){
return NO;
}
return [stringA isEqualToString:stringB];
}
@end
网友评论