phonegap+激光推送做ios的消息推送

*光推送插件地址:https://github.com/jpush/jpush-phonegap-plugin

1.cordova,git 环境

2.过程遇到的错误

将这个包再次导入

%title插图%num

%title插图%num

修改一处地方

%title插图%num

字典里appkey的修改

%title插图%num

3.

登陆并加标注
var onDeviceReady = function(){
console.log(“JPushPlugin:Device ready!”);
initiateUI();
}
var initiateUI = function(){
try{
window.plugins.jPushPlugin.init();
if(device.platform != “Android”){
window.plugins.jPushPlugin.setBadge(0);//服务器角标清0
window.plugins.jPushPlugin.setDebugModeFromIos();
window.plugins.jPushPlugin.setApplicationIconBadgeNumber(0);//角标
}else{
window.plugins.jPushPlugin.setDebugMode(true);
}
var alias=userName;
window.plugins.jPushPlugin.setAlias(alias);
}catch(exception){
console.log(exception);
}

}
document.addEventListener(“deviceready”, onDeviceReady, false);//初始化设备

4.公用函数的加载

//检索是否session过期

function checkSession(){
try{
$.post(conn+”ds=DS_EASYJOINT_MOBIL_GROUP_LIST”,{},function(data){
var nowHref=window.location.href;
if((data.indexOf(“html”)>-1) && nowHref.indexOf(“login.html”)==-1){
window.location.href=”login.html”;
}
});
}catch(e){
console.log(“checkSession:”+e);
}
}

//推送函数
//window.plugins.jPushPlugin.resumePush(callback)
//var onCallback = function(data) {
// if(data>0){
// //开启
// }else{
// //关闭
// }
//}
function pushMessage(){
var openNotification = function(event){
try{
window.plugins.jPushPlugin.setBadge(0);//服务器角标清0
window.plugins.jPushPlugin.setDebugModeFromIos();
window.plugins.jPushPlugin.setApplicationIconBadgeNumber(0);
checkSession();//过期
}
catch(exception){
console.log(“jpush.openNotification”+exception);
}
}

function onDeviceReadyPush() {
document.addEventListener(“resume”, onResume, false);
window.plugins.jPushPlugin.init();
}
// 处理resume事件
function onResume() {
try{
window.plugins.jPushPlugin.setBadge(0);//服务器角标清0
window.plugins.jPushPlugin.setDebugModeFromIos();
window.plugins.jPushPlugin.setApplicationIconBadgeNumber(0);//角标
checkSession();//过期
}
catch(exception){
console.log(exception);
}
}
document.addEventListener(“deviceready”, onDeviceReadyPush, false);
document.addEventListener(“jpush.openNotification”, openNotification, false);
}

$(function(){
pushMessage();//推送
});

 

IOS高级开发~开机启动&无限后台运行&监听进程

非越狱情况下实现:

开机启动:App安装到IOS设备设备之后,无论App是否开启过,只要IOS设备重启,App就会随之启动;

无限后台运行:应用进入后台状态,可以无限后台运行,不被系统kill;

监听进程:可获IOS设备运行除系统外的App(包括正在运行和后台运行);

配置项目 plist文件

添加:

<key>UIBackgroundModes</key>

<array>

<string>voip</string>

</array>

功能类:ProccessHelper

  1. #import <Foundation/Foundation.h>
  2. @interface ProccessHelper : NSObject
  3. + (NSArray *)runningProcesses;
  4. @end
  5. [cpp] view plaincopyprint?
  6. #import “ProccessHelper.h”
  7. //#include<objc/runtime.h>
  8. #include <sys/sysctl.h>
  9. #include <stdbool.h>
  10. #include <sys/types.h>
  11. #include <unistd.h>
  12. #include <sys/sysctl.h>
  13. @implementation ProccessHelper
  14. //You can determine if your app is being run under the debugger with the following code from
  15. static bool AmIBeingDebugged(void)
  16. // Returns true if the current process is being debugged (either
  17. // running under the debugger or has a debugger attached post facto).
  18. {
  19. int junk;
  20. int mib[4];
  21. struct kinfo_proc info;
  22. size_t size;
  23. // Initialize the flags so that, if sysctl fails for some bizarre
  24. // reason, we get a predictable result.
  25. info.kp_proc.p_flag = 0;
  26. // Initialize mib, which tells sysctl the info we want, in this case
  27. // we’re looking for information about a specific process ID.
  28. mib[0] = CTL_KERN;
  29. mib[1] = KERN_PROC;
  30. mib[2] = KERN_PROC_PID;
  31. mib[3] = getpid();
  32. // Call sysctl.
  33. size = sizeof(info);
  34. junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
  35. assert(junk == 0);
  36. // We’re being debugged if the P_TRACED flag is set.
  37. return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
  38. }
  39. //返回所有正在运行的进程的 id,name,占用cpu,运行时间
  40. //使用函数int sysctl(int *, u_int, void *, size_t *, void *, size_t)
  41. + (NSArray *)runningProcesses
  42. {
  43. //指定名字参数,按照顺序*个元素指定本请求定向到内核的哪个子系统,第二个及其后元素依次细化指定该系统的某个部分。
  44. //CTL_KERN,KERN_PROC,KERN_PROC_ALL 正在运行的所有进程
  45. int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL ,0};
  46. size_t miblen = 4;
  47. //值-结果参数:函数被调用时,size指向的值指定该缓冲区的大小;函数返回时,该值给出内核存放在该缓冲区中的数据量
  48. //如果这个缓冲不够大,函数就返回ENOMEM错误
  49. size_t size;
  50. //返回0,成功;返回-1,失败
  51. int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
  52. struct kinfo_proc * process = NULL;
  53. struct kinfo_proc * newprocess = NULL;
  54. do
  55. {
  56. size += size / 10;
  57. newprocess = realloc(process, size);
  58. if (!newprocess)
  59. {
  60. if (process)
  61. {
  62. free(process);
  63. process = NULL;
  64. }
  65. return nil;
  66. }
  67. process = newprocess;
  68. st = sysctl(mib, miblen, process, &size, NULL, 0);
  69. } while (st == -1 && errno == ENOMEM);
  70. if (st == 0)
  71. {
  72. if (size % sizeof(struct kinfo_proc) == 0)
  73. {
  74. int nprocess = size / sizeof(struct kinfo_proc);
  75. if (nprocess)
  76. {
  77. NSMutableArray * array = [[NSMutableArray alloc] init];
  78. for (int i = nprocess – 1; i >= 0; i–)
  79. {
  80. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  81. NSString * processID = [[NSString alloc] initWithFormat:@”%d”, process[i].kp_proc.p_pid];
  82. NSString * processName = [[NSString alloc] initWithFormat:@”%s”, process[i].kp_proc.p_comm];
  83. NSString * proc_CPU = [[NSString alloc] initWithFormat:@”%d”, process[i].kp_proc.p_estcpu];
  84. double t = [[NSDate date] timeIntervalSince1970] – process[i].kp_proc.p_un.__p_starttime.tv_sec;
  85. NSString * proc_useTiem = [[NSString alloc] initWithFormat:@”%f”,t];
  86. NSString *startTime = [[NSString alloc] initWithFormat:@”%ld”, process[i].kp_proc.p_un.__p_starttime.tv_sec];
  87. NSString * status = [[NSString alloc] initWithFormat:@”%d”,process[i].kp_proc.p_flag];
  88. NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
  89. [dic setValue:processID forKey:@”ProcessID”];
  90. [dic setValue:processName forKey:@”ProcessName”];
  91. [dic setValue:proc_CPU forKey:@”ProcessCPU”];
  92. [dic setValue:proc_useTiem forKey:@”ProcessUseTime”];
  93. [dic setValue:proc_useTiem forKey:@”ProcessUseTime”];
  94. [dic setValue:startTime forKey:@”startTime”];
  95. // 18432 is the currently running application
  96. // 16384 is background
  97. [dic setValue:status forKey:@”status”];
  98. [processID release];
  99. [processName release];
  100. [proc_CPU release];
  101. [proc_useTiem release];
  102. [array addObject:dic];
  103. [startTime release];
  104. [status release];
  105. [dic release];
  106. [pool release];
  107. }
  108. free(process);
  109. process = NULL;
  110. //NSLog(@”array = %@”,array);
  111. return array;
  112. }
  113. }
  114. }
  115. return nil;
  116. }
  117. @end

 

实现代码:

  1. systemprocessArray = [[NSMutableArray arrayWithObjects:
  2. @”kernel_task”,
  3. @”launchd”,
  4. @”UserEventAgent”,
  5. @”wifid”,
  6. @”syslogd”,
  7. @”powerd”,
  8. @”lockdownd”,
  9. @”mediaserverd”,
  10. @”mediaremoted”,
  11. @”mDNSResponder”,
  12. @”locationd”,
  13. @”imagent”,
  14. @”iapd”,
  15. @”fseventsd”,
  16. @”fairplayd.N81″,
  17. @”configd”,
  18. @”apsd”,
  19. @”aggregated”,
  20. @”SpringBoard”,
  21. @”CommCenterClassi”,
  22. @”BTServer”,
  23. @”notifyd”,
  24. @”MobilePhone”,
  25. @”ptpd”,
  26. @”afcd”,
  27. @”notification_pro”,
  28. @”notification_pro”,
  29. @”syslog_relay”,
  30. @”notification_pro”,
  31. @”springboardservi”,
  32. @”atc”,
  33. @”sandboxd”,
  34. @”networkd”,
  35. @”lsd”,
  36. @”securityd”,
  37. @”lockbot”,
  38. @”installd”,
  39. @”debugserver”,
  40. @”amfid”,
  41. @”AppleIDAuthAgent”,
  42. @”BootLaunch”,
  43. @”MobileMail”,
  44. @”BlueTool”,
  45. nil] retain];

 

  1. – (void)applicationDidEnterBackground:(UIApplication *)application
  2. {
  3. while (1) {
  4. sleep(5);
  5. [self postMsg];
  6. }
  7. [cpp] view plaincopyprint?
  8. [[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{
  9. NSLog(@”KeepAlive”);
  10. }];
  11. }
  12. – (void)applicationWillResignActive:(UIApplication *)application
  13. {
  14. }
  15. – (void)applicationWillEnterForeground:(UIApplication *)application
  16. {
  17. }
  18. – (void)applicationDidBecomeActive:(UIApplication *)application
  19. {
  20. }
  21. – (void)applicationWillTerminate:(UIApplication *)application
  22. {
  23. }
  24. #pragma mark –
  25. #pragma mark – User Method
  26. – (void) postMsg
  27. {
  28. //上传到服务器
  29. NSURL *url = [self getURL];
  30. NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
  31. NSError *error = nil;
  32. NSData *received = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
  33. if (error) {
  34. NSLog(@”error:%@”, [error localizedDescription]);
  35. }
  36. NSString *str = [[NSString alloc]initWithData:received encoding:NSUTF8StringEncoding];
  37. NSLog(@”%@”,str);
  38. }
  39. – (NSURL *) getURL
  40. {
  41. UIDevice *device = [UIDevice currentDevice];
  42. NSString* uuid = @”TESTUUID”;
  43. NSString* manufacturer = @”apple”;
  44. NSString* model = [device model];
  45. NSString* mobile = [device systemVersion];
  46. NSString *msg = [NSString stringWithFormat:@”Msg:%@ Time:%@”, [self processMsg], [self getTime]];
  47. CFShow(msg);
  48. / 省略部分代码 /
  49. NSString *urlStr = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  50. NSURL *url = [NSURL URLWithString:urlStr];
  51. return url;
  52. }
  53. – (BOOL) checkSystemProccess:(NSString *) proName
  54. {
  55. if ([systemprocessArray containsObject:proName]) {
  56. return YES;
  57. }
  58. return NO;
  59. }
  60. – (BOOL) checkFirst:(NSString *) string
  61. {
  62. NSString *str = [string substringToIndex:1];
  63. NSRange r = [@”ABCDEFGHIJKLMNOPQRSTUVWXWZ” rangeOfString:str];
  64. if (r.length > 0) {
  65. return YES;
  66. }
  67. return NO;
  68. }
  69. – (NSString *) processMsg
  70. {
  71. NSArray *proMsg = [ProccessHelper runningProcesses];
  72. if (proMsg == nil) {
  73. return nil;
  74. }
  75. NSMutableArray *proState = [NSMutableArray array];
  76. for (NSDictionary *dic in proMsg) {
  77. NSString *proName = [dic objectForKey:@”ProcessName”];
  78. if (![self checkSystemProccess:proName] && [self checkFirst:proName]) {
  79. NSString *proID = [dic objectForKey:@”ProcessID”];
  80. NSString *proStartTime = [dic objectForKey:@”startTime”];
  81. if ([[dic objectForKey:@”status”] isEqualToString:@”18432″]) {
  82. NSString *msg = [NSString stringWithFormat:@”ProcessName:%@ – ProcessID:%@ – StartTime:%@ Running:YES”, proName, proID, proStartTime];
  83. [proState addObject:msg];
  84. } else {
  85. NSString *msg = [NSString stringWithFormat:@”ProcessName:%@ – ProcessID:%@ – StartTime:%@ Running:NO”, proName, proID, proStartTime];
  86. [proState addObject:msg];
  87. }
  88. }
  89. }
  90. NSString *msg = [proState componentsJoinedByString:@”______”];
  91. return msg;
  92. }
  93. // 获取时间
  94. – (NSString *) getTime
  95. {
  96. NSDateFormatter *formatter =[[[NSDateFormatter alloc] init] autorelease];
  97. formatter.dateStyle = NSDateFormatterMediumStyle;
  98. formatter.timeStyle = NSDateFormatterMediumStyle;
  99. formatter.locale = [NSLocale currentLocale];
  100. NSDate *date = [NSDate date];
  101. [formatter setTimeStyle:NSDateFormatterMediumStyle];
  102. NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
  103. NSDateComponents *comps = [[[NSDateComponents alloc] init] autorelease];
  104. NSInteger unitFlags = NSYearCalendarUnit |
  105. NSMonthCalendarUnit |
  106. NSDayCalendarUnit |
  107. NSWeekdayCalendarUnit |
  108. NSHourCalendarUnit |
  109. NSMinuteCalendarUnit |
  110. NSSecondCalendarUnit;
  111. comps = [calendar components:unitFlags fromDate:date];
  112. int year = [comps year];
  113. int month = [comps month];
  114. int day = [comps day];
  115. int hour = [comps hour];
  116. int min = [comps minute];
  117. int sec = [comps second];
  118. NSString *time = [NSString stringWithFormat:@”%d-%d-%d %d:%d:%d”, year, month, day, hour, min, sec];
  119. return time;
  120. }
  121. @end

IOS 学习总结之动画

  1. UIView的,翻转、旋转,偏移,翻页,缩放,取反的动画效果
  2. 翻转的动画
  3. //开始动画
  4. [UIView beginAnimations:@”doflip” context:nil];
  5. //设置时常
  6. [UIView setAnimationDuration:1];
  7. //设置动画淡入淡出
  8. [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
  9. //设置代理
  10. [UIView setAnimationDelegate:self];
  11. //设置翻转方向
  12. [UIView setAnimationTransition:
  13. UIViewAnimationTransitionFlipFromLeft forView:manImageView cache:YES];
  14. //动画结束
  15. [UIView commitAnimations];
  16. 旋转动画
  17. 创建一个CGAffineTransform transform对象
  18. CGAffineTransform transform;
  19. //设置旋转度数
  20. transform = CGAffineTransformRotate(manImageView.transform,M_PI/6.0);
  21. //动画开始
  22. [UIView beginAnimations:@”rotate” context:nil ];
  23. //动画时常
  24. [UIView setAnimationDuration:2];
  25. //添加代理
  26. [UIView setAnimationDelegate:self];
  27. //获取transform的值
  28. [manImageView setTransform:transform];
  29. //关闭动画
  30. [UIView commitAnimations];
  31. 偏移动画
  32. [UIView beginAnimations:@”move” context:nil];
  33. [UIView setAnimationDuration:2];
  34. [UIView setAnimationDelegate:self];
  35. //改变它的frame的x,y的值
  36. manImageView.frame=CGRectMake(100,100, 120,100);
  37. [UIView commitAnimations];
  38. 翻页动画
  39. [UIView beginAnimations:@”curlUp” context:nil];
  40. [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];//指定动画曲线类型,该枚举是默认的,线性的是匀速的
  41. //设置动画时常
  42. [UIView setAnimationDuration:1];
  43. [UIView setAnimationDelegate:self];
  44. //设置翻页的方向
  45. [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:manImageView cache:YES];
  46. //关闭动画
  47. [UIView commitAnimations];
  48. 缩放动画
  49. CGAffineTransform transform;
  50. transform = CGAffineTransformScale(manImageView.transform,1.2,1.2);
  51. [UIView beginAnimations:@”scale” context:nil];
  52. [UIView setAnimationDuration:2];
  53. [UIView setAnimationDelegate:self];
  54. [manImageView setTransform:transform];
  55. [UIView commitAnimations];
  56. 取反的动画效果是根据当前的动画取他的相反的动画
  57. CGAffineTransform transform;
  58. transform=CGAffineTransformInvert(manImageView.transform);
  59. [UIView beginAnimations:@”Invert” context:nil];
  60. [UIView setAnimationDuration:2];//动画时常
  61. [UIView setAnimationDelegate:self];
  62. [manImageView setTransform:transform];//获取改变后的view的transform
  63. [UIView commitAnimations];//关闭动画

zxing 二维码扫描 配置和使用

二维码扫描使用*多的主要有两个库:zbarSDK 和zxing

关于zbar的使用比较简单,在这里不多说了,对于zxing的使用就比较麻烦,虽然网上有很多关于zxing的使用方法,不过查了很多中文和英文的贴子。发现说的都不够详细,对与像我这样*次搞的新手来说差一步就错了很多!

现在根据自己项目中使用的情况,详细具体的总结一下如何将ZXing集成到已有的iOS工程中

*步:首先去Google Code或Github将ZXing的代码下载下来(ZXing(Github镜像地址)),整个工程比较大,我们只需要其中涉及iOS的部分,所以*好做一些裁剪。简单来说,我们只需要保留cpp和iphone这2个文件夹,其余的全部删掉。如下图所示:

%title插图%num

第二步:裁剪,对于cpp这个目录,只保留cpp/core/src/zxing下面的内容,其余内容也可以删掉了。同样对iphone这个目录只需要保存 iphone/ZXingWidget/下面的内容,但是整个目录结构必须保持原样。裁剪完后,整个目录结构如下所示:

%title插图%num

第三步:首先将修该后的zxing上面的开发包(即上面修改后的zxing文件夹),拷贝到你的项目根文件夹下面;

添加文件到你的工程中,选择“Add filesto…”,在弹出的框中,找到:你的项目文件夹/zxing/iphone/ZXingWidget下面的ZXingWidget.xcodeproj,选择”ZXingWidget.xcodeproj”,在添加前,请先运行该项目,进行编译,如果成功,再进行此步添加!

添加成功后项目结构如下图:

%title插图%num

第四步:选择你的项目–TARGETS–Build Phases—Target Dependencies—-然后点击”+”添加“ZXingWidget”。添加后如下图:

%title插图%num
第五步:

同样,添加frameWorks.方法:Build Phases—Target Dependencies—-”Link Binary With Libraries”—点击”+”。添加如下几项:

libZXingWidget.a

AddressBook

AddressBookUI

AudioToolbox

AVFoundation

CoreMedia

CoreVideo

libiconv.dylib

完成后如下图:

%title插图%num

第六步:后一步,在设置中增加如下2个header search path:

1. BuildSettings — 2.搜索”header search paths” — 3.双击”HeaderSearch Paths”

/zxing/iphone/ZXingWidget/Classes
./zxing/cpp/core/src
需要注意的是,*个path要设置成循环查找子目录,而第二个不循环查找,如下图所示:

%title插图%num

完成这一步,就已经完成了ZXing库的集成工作,(如果不做修改的话,zxing暂时只能识别二维码,不能识别条形码)

在这里编译工程,应该能成功,不会报错,如果有报错信息等,看看是否是少添加了库,Header Search Paths中的路径是否正确;

 

在项目中引用

首先将你使用ZXingWidgetController的文件的后缀该为.mm, 例如:我在MyZxingViewController.m改为:MyZxingViewController.mm否则在使用的时候会报:xxx filenot found的类似的问题

同时你必须将 #import<ZXingWidgetController.h>添加到你的.h文件中将

#import <QRCodeReader.h>

#import <MultiFormatOneDReader.h>添加到.mm文件中,否则也会报iostream file not found类似的问题

 

MyZxingViewController文件夹中引用

.h

#import <UIKit/UIKit.h>

#import “ZXingWidgetController.h”

//#import “QRCodeReader.h”//这个引用在.h文件中为出错:iostream file not found

@interface Contact : UIViewController <ZXingDelegate>{

UITextView *resultsView;

NSString *resultsToDisplay;

}

@property (retain, nonatomic) IBOutlet UITextView *resultsView;

@property (nonatomic, copy) NSString *resultsToDisplay;

– (IBAction)scanPressed:(id)sender;

@end

 

具体用法可以参考ZXing(Github镜像地址)中的例子

 

修改zxing 使其能扫描条形码

例子中的代码确实只能做二维码的识别, 不能做条形码的扫描。 研究了一下又在网上找了一下,  结果发现稍做修改,还是可以让ZXing支持条形码和二维码的同时识别的, 代码稍侯就贴出来。本人亲自试过,确实可行。

总结地来说, ZBar使用起来比ZXing相对方便一点, 也就是更像是 卡片机与单反相机的区别。但如果需要修改代码的话,做一些自定义什么的,建议使用ZXing, 如果只是想随便用用的话, 建议使用ZBar.

好,话不多说, 下面说说如何使ZXing改改后可以支持扫条形码。

1.在- (IBAction)scanPressed:(id)sender方法中:
ZXingWidgetController*widController = [[ZXingWidgetControlleralloc] initWithDelegate:selfshowCancel:YESOneDMode:YES];
MultiFormatOneDReader*OneReaders=[[MultiFormatOneDReader alloc]init];
QRCodeReader* qrcodeReader = [[QRCodeReader alloc] init];
NSSet*readers = [[NSSet alloc] initWithObjects:OneReaders,qrcodeReader,nil];
[qrcodeReader release];[OneReaders release];
2.在ZXingWidgetController.m的(void)captureOutput:(AVCaptureOutput *)captureOutput :方法中,注释掉以下方法
if(oneDMode) {

// let’s just give the decoder a vertical band right above the red line

cropRect.origin.x = cropRect.origin.x + (cropRect.size.width / 2) – (ONE_D_BAND_HEIGHT + 1);

cropRect.size.width = ONE_D_BAND_HEIGHT;

// do a rotate

CGImageRef croppedImg = CGImageCreateWithImageInRect(capture, cropRect);

capture = [selfCGImageRotated90:croppedImg];

capture = [selfCGImageRotated180:capture];

//              UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage:capture], nil, nil, nil);

CGImageRelease(croppedImg);

cropRect.origin.x = 0.0;

cropRect.origin.y = 0.0;

cropRect.size.width = CGImageGetWidth(capture);

cropRect.size.height = CGImageGetHeight(capture);

}

 

3. 将上面注释掉的代码向下数大概约20行处的代码:UIImage *scrn = [[UIImage alloc] initWithCGImage:newImage]; 改为:int backCameraImageOrientation = UIImageOrientationRight; UIImage *scrn = [[UIImage alloc] initWithCGImage:newImage scale: (CGFloat)1.0 orientation:backCameraImageOrientation];

4. 在OverlayView.m注释代码以下代码:

self.oneDMode = isOneDModeEnabled;
然后运行 , 会发现可扫条形码了 ,   还可以同时扫二维码了

ZXing 二维码 For IOS 配置以及使用

ZXing(Github镜像地址)是一个开源的条码生成和扫描库(开源协议为Apache2.0)。它不但支持众多的条码格式,而且有各种语言的实现版本,它支持的语言包括:Java, C++, C#, Objective-C, ActionScript和Ruby。

ZBar一般都是直接使用现成的静态库就好了,除非自己要自定义一些功能。zxing也可以但是要包含好多 头文件,还是直接引用工程方便。
下面是具体步骤:
 1.在github 下载zxing开源的代码https://github.com/zxing/zxing。
2.我们保留我们需要的cpp和iphone这2个文件夹,其余的全部删掉。如下图所示
%title插图%num
%title插图%num
3.对于cpp这个目录,只保留cpp/core/src/zxing下面的内容,其余内容也可以删掉了。但是整个目录结构必须保持原样。裁剪完后,整个目录结构如下所示:
%title插图%num
%title插图%num
4.接下来,我们把裁剪后的zxing目录整个移动到你自己的项目的根目录下,并且把上图中可以看到的ZXingWidget.xcodeproj文件拖动到你的iOS工程中。

%title插图%num%title插图%num

二:

%title插图%num%title插图%num

5.我们需要设置ZXing项目和我们原本的iOS项目之间的依赖关系。在我们的iOS项目的设置中,点击build phases tab,然后增加 Target Dependencies 和 Link binary,并且增加这些framework依赖:

完成之后如下图:

%title插图%num%title插图%num

二:

%title插图%num%title插图%num

*后一步,在设置中增加如下2个header search path:

 

./zxing/iphone/ZXingWidget/Classes

./zxing/cpp/core/src

需要注意的是,*个path要设置成循环查找子目录,而第二个不循环查找,如下图所示:

%title插图%num

注意:我在使用中遇到了一些问题,主要是编译的问题。

 

1.一个是找不到 头文件。解决方法:把用到ZXing的源文件扩展名由.m改成.mm。

2.报错:Undefined symbols for architecture armv7s,解决方法:把ZXingWidget的一个build target参数:”Build Active Architecture Only” 修改成 “NO”.

%title插图%num%title插图%num

3.报错:No such file or directory,出现该错误可能是你的Header Search Path写错了,或者就是你的zxing库的目录结构不是我上面强调的,好好检查一下吧。

4.如果遇到下面问题:

std::allocator<char> const&)", referenced from:  
  
(null): "std::string::append(std::string const&)", referenced from:  
  
(null): "std::__throw_out_of_range(char const*)", referenced from:  
  
(null): "std::ios_base::Init::Init()", referenced from:  
  
(null): "std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)", referenced from:  
  
(null): "std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_ostringstream()", referenced from:  
  
(null): "std::string::append(unsigned long, char)", referenced from:  
  
(null): "std::string::_M_leak_hard()", referenced from:  
  
(null): "std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::str() const", referenced from:  
  
(null): "std::string::erase(unsigned long, unsigned long)", referenced from:
(null): Linker command failed with exit code 1 (use -v to see invocation)

 

就是C++编译器的设置问题

在Build Settings里我们设置一下:

%title插图%num%title插图%num

这样就ok了。

如果再提示

Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_QRCodeReader", referenced from:
      objc-class-ref in ViewController.o
  "_OBJC_CLASS_$_ZXingWidgetController", referenced from:
      objc-class-ref in ViewController.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

那是zxing不支持*新的arm64架构,改两个地方

1.选armv7和armv7s

%title插图%num

2.删除arm64

%title插图%num

 

如果要加入生成二维码的功能,从下面的链接下载Zxing Demo

http://code4app.com/ios/ZXing-Demo/515561f76803fa5e77000002

 

1.首先把ThirdParty这个文件夹拖到自己的工程里面来,注意是跟main.n在同一级目录,如下图

%title插图%num

注意QRCodeEncoderObjectiveCAtGithub.xcodeproj的targets

%title插图%num

在项目的targets里面加入这两个

%title插图%num

下面这个要注意,ZXingDemo是示例工程名,这里要改成自己项目的名称。

%title插图%num

通过 PhoneGap 使用 Apple 推送通知

 要求

其他必要产品

本文至少需要具备中级 PhoneGap 开发经验。

用户级别

中级

范例文件

  • PhoneGap Apple Push Notifications Plugin on GitHub

在这篇文章中,我将会介绍如何在 PhoneGap 移动应用程序中使用 Apple Push Notifications (APNs)。推送通知与本地通知的区别在于,推送通知是从第三方服务器向用户发送通知,而本地通知则由应用程序调度并在设备本身运行,不存在任何服务器交互。

例如,您可能会收到 Facebook 发送的大量推送通知,通知您某人将您加为好友,或者如果您是《填字游戏》(Words With Friends) 玩家,则可能会收到推送通知,表明轮到您填字了。本地通知的一个典型例子是,如果您为一个任务设置了日期/时间,系统会在一定的时间或以一定的时间间隔弹出提示进行提醒;在特定的时间会有提示弹出来对您进行提醒。对于*终用户而言,两种通知的显示形式完全相同,它们都会弹出提示,并且可以伴有相关声音及其他功能,但从开发角度来讲,两者却截然不同。

在 iOS 中,无论是本地通知还是推送通知都要用到 Cordova/PhoneGap 插件,但本系列教程将重点介绍如何开发推送通知。如果想要了解如何开发 Android 推送通知,这里还提供了推送通知的概念,但设置和过程略有不同,我们将会在另一篇文章中进行介绍。

以创建 APN 开启整个过程起初可能会觉得有些恐怖,但花时间开展这项工作*对值得,因为用例无穷无尽。本文旨在帮助您了解整个过程,包括创建过程以及应用程序和服务器端发生的事情,通过示例代码让您快速起步。

APN 工作流程说明

要开始操作,*好了解 Apple Push Notifications (APN) 的工作流程。

  • 一经启动,您的应用程序就会与 Apple Push Notification Service 通信,授权它接收推送通知。
  • Apple 会返回一个独特的令牌,供用户在所有未来通信中用来接收推送通知。
  • 您的应用程序将该令牌发送至第三方服务器(您自身的提供商或其他某个提供商,如 Urban Airship)进行存储,以便在日后需要向应用程序发送通知时使用。

图 1. Apple Push Notifications 的工作流程。

图片制作者:Ray Wenderlich。

SSL 证书和配置

不要让这个步骤吓住,一旦您开始操作,就会发现它并不那么可怕。Ray Wenderlich 创作了一篇不错的文章,Apple Push Notification Services 教程:第 1 部分(共 2 部分),其中记录了这个过程,并配有屏幕截图和细节信息,您将会在执行此步骤期间用到。

下面概括介绍一下您应当执行哪些操作,使应用程序启用推送通知。首先,您的应用程序需要使用 App ID (com.mysite.myapp) 通过 Apple iOS Provisioning Portal 启用推送通知,并通过包含支持推送功能的应用程序标识符的配置文件进行签名。接下来,您还需要将 App ID 与 SSL 证书关联起来,以便安全地与 Apple Push Notification Server 进行通信。当您通过该门户配置 App ID 时,向导将提示您创建 SSL 证书,该证书将与您的 App ID 关联,用于开展通信。与 App ID 关联可确保从您的服务器发送到 Apple APN Server 的通知仅会发送到 ID 匹配的应用程序。

证书流程完成后,为这个包含有效推送通知的新 App ID 下载一个新的配置文件。然后,将它拖动到 XCode 中,确保它就是您在 Code Signing 屏幕(位于项目的 “Build Settings” 下)中为您的应用程序选择的配置文件。

创建您的应用程序

本文假设您了解如何创建项目,包括 PhoneGap/Cordova,如果您不了解相关知识,请参阅PhoneGap/Cordova 网站的“iOS 入门”部分。现在,您已经准备好开始执行 HTML/JavaScript/PhoneGap 应用程序编码,我们来执行以下步骤创建该应用程序。

  1. 从 GitHub 获取*新的 PhoneGap Push Notifications 插件。
  2. 将 PushNotification 文件夹拖放到 XCode 中的 Plugins 文件夹。在复制选项中,选择 Create groups for any added folders,如屏幕截图中所示。

图 2. 创建您的应用程序。

  1. 离开 XCode,进入 Finder,并将 PushNotification.js 文件复制到 www\plugins(www 文件夹下的插件子文件夹)。它将自动出现在您的 XCode 中。
  2. 添加脚本标记,以便在 HTML 文件中引用 PushNotification.js 文件,如下所示:
    <script src=”js/plugins/PushNotification.js”></script>
  3. 将插件密钥和值添加到您的 Cordova.plist(在项目资源根文件夹下查找此文件)。

图 3. 将插件添加到您的Cordova.plist。

Cordova PushNotification 插件为您提供了一个很好的 JavaScript API,您可以从 HTML/JS 文件使用它来与底层本机代码进行交互,以处理注册并接收推送通知。部分函数如下所示:

  • registerDevice()
  • setApplicationIconBadgeNumber()
  • getRemoteNotificationStatus()
  • getPendingNotifications()

尽管如此,要使用 JavaScript API,您首先需要向本机应用程序代码中添加一些内容,以便连接特定的推送通知代码。应用程序的 AppDelegate 类(位于项目类文件夹下)用于实现应用程序级事件(如应用程序启动、终止等)处理程序。您还可以使用其他事件处理通知。您可以在 Handling Notifications 引用中查看事件列表。

默认情况下不会实现这些方法;不过,为了提供支持,您必须添加代码处理程序,并将它们委托给插件代码中纳入的 PushNotification.m 类。要添加的代码会显示在该插件的 README 文件中,但我们也会在这里进行讨论。您当前基本上需要处理以下三种事件:

  • didReceiveRemoteNotification
  • didRegisterForRemoteNotificationsWithDeviceToken
  • didFailToRegisterForRemoteNotificationsWithError

在 AppDelegate.m 类的 @end 前面添加下列代码块,以处理通知事件:

/* START BLOCK */
#pragma PushNotification delegation

– (void)application:(UIApplication*)app
didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
PushNotification* pushHandler = [self.viewController getCommandInstance:@”PushNotification”];
[pushHandler didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

– (void)application:(UIApplication*)app didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
PushNotification* pushHandler = [self.viewController getCommandInstance:@”PushNotification”];
[pushHandler didFailToRegisterForRemoteNotificationsWithError:error];
}

– (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
PushNotification* pushHandler = [self.viewController getCommandInstance:@”PushNotification”];
NSMutableDictionary* mutableUserInfo = [userInfo mutableCopy];

// Get application state for iOS4.x+ devices, otherwise assume active
UIApplicationState appState = UIApplicationStateActive;
if ([application respondsToSelector:@selector(applicationState)]) {
appState = application.applicationState;
}

[mutableUserInfo setValue:@”0″ forKey:@”applicationLaunchNotification”];
if (appState == UIApplicationStateActive) {
[mutableUserInfo setValue:@”1″ forKey:@”applicationStateActive”];
[pushHandler didReceiveRemoteNotification:mutableUserInfo];
} else {
[mutableUserInfo setValue:@”0″ forKey:@”applicationStateActive”];
[mutableUserInfo setValue:[NSNumber numberWithDouble: [[NSDate date] timeIntervalSince1970]] forKey:@”timestamp”];
[pushHandler.pendingNotifications addObject:mutableUserInfo];
}
}
/* STOP BLOCK */

从本质上而言,上面的代码用于创建 PushNotification 类引用。它会根据发生的事件设置或读取某些值,或者通过参数调用不同的方法。就算对 Objective-C 一无所知或者认为此处十分复杂也不用担心,我在“要求”部分提供了示例项目供您下载参考。

*后,向同一个 AppDelegate.m 类的 didFinishLaunchingWithOptions 方法中添加代码片段,以便从通知打开该应用程序(并将收到的对象添加到 pendingNotifications 供日后检索)。在结尾的 return YES前面添加此代码块,如下所示:

/* Handler when launching application from push notification */
// PushNotification – Handle launch from a push notification
NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(userInfo) {
PushNotification *pushHandler = [self.viewController getCommandInstance:@”PushNotification”];
NSMutableDictionary* mutableUserInfo = [userInfo mutableCopy];
[mutableUserInfo setValue:@”1″ forKey:@”applicationLaunchNotification”];
[mutableUserInfo setValue:@”0″ forKey:@”applicationStateActive”];
[pushHandler.pendingNotifications addObject:mutableUserInfo];
}
/* end code block */

PushNotification 插件 – JavaScript API

现在,您已经完成了项目创建,包括上面的本机 Objective-C 处理程序,可以实际使用 Cordova PushNotification JavaScript 界面开始编码。下面是有关部分内容的进一步详情,以及以代码的形式开展互动的例子。还有一些其他方面,但我并未在本文中进行具体介绍。

注册设备

PhoneGap PushNotification 插件提供了 registerDevice() API,用于通过 Apple Push Notification Service 注册您的应用程序以接收推送通知。在该函数中,您可以明确指定支持哪些类型的通知 (alerts/badges/sounds)。结果会返回一个独特的设备令牌,以便服务器端以此向该设备发送通知。Apple 建议您每次在设备上运行推送通知时均注册应用程序使用推送通知,因为令牌可能会发生变化。

示例项目中提供了一个 registerDevice() 函数示例,您可以在本文开头的“要求”部分进行下载。我在下面展示了这个代码。

var pushNotification = window.plugins.pushNotification;
pushNotification.registerDevice({alert:true, badge:true, sound:true}, function(status) {
app.myLog.value+=JSON.stringify([‘registerDevice status: ‘, status])+”\n”;
app.storeToken(status.deviceToken);
});

上面的代码编写完成且应用程序运行后,您将会收到图 4 中显示的警报,询问用户是否要接收推送通知(单击 “OK” 或 “Don’t Allow”,将会显示一项设置,用户可以根据自身的设备设置进行修改)。

图 4. 要求获得发送推送通知权限的提示。

获取未决通知

未决通知是指应用程序处于非活动状态时收到的通知。当应用程序启动时,检索这些通知,以便根据需要处理数据并发送数据。API 中的 getPendingNotifications() 函数可用于达成这一目的。请参阅下面的示例代码:

var pushNotification = window.plugins.pushNotification;
pushNotification.getPendingNotifications(function(notifications) {
app.myLog.value+=JSON.stringify([‘getPendingNotifications’, notifications])+”\n”;
console.log(JSON.stringify([‘getPendingNotifications’, notifications]));
});

获取通知状态

此方法用于执行注册检查,并返回启用的通知(警报、声音、徽章)。

var pushNotification = window.plugins.pushNotification;
pushNotification.getRemoteNotificationStatus(function(status) {
app.myLog.value+=JSON.stringify([‘Registration check -getRemoteNotificationStatus’, status])+”\n”;
});

设置徽章编号

徽章编号是指通过在应用程序图标右上角显示编号来表示特定应用程序的未决通知的方法。您很可能需要在处理通知时于应用程序图标上设置徽章编号。例如,如果从您刚刚收到的推送通知中打开,您可能希望减少或消除编号。将徽标编号设置为零,可删除或清除徽标,如下所示。

var pushNotification = window.plugins.pushNotification;
app.myLog.value+=”Clear badge… \n”;
pushNotification.setApplicationIconBadgeNumber(num);

剖析 Apple Push Notification

通知有效负载的*大值为 256 字节。如果超出这个限制,将会遭到拒*。同时注意,Apple 文档明确说明,通知交付是“尽力而为”但并不作相应保证,因此不应用它来发送关键数据或敏感数据,只能用于通知是否存在新的可用数据。

通知有效负载是 JSON 字典对象,需要包含由主要 aps 识别的另一个字典。紧接着,aps 字典将包含用于指定要显示的警报的一个或多个属性、应用程序图标上要设置的徽标编号和/或出现通知时要播放的声音。它还可以创建自定义有效负载,但本文不会就此进行介绍。警报对象本身只需包含一个要显示的文本字符串或带有正文密钥的字典对象、要显示的自定义操作按钮文本和可以设置的自定义启动图像。请在 Apple Push Notification Service 文档中查看有关有效负载的具体细节信息。

下面是一个简单的有效负载示例(单位:字节):

图 5. Apple Push Notifications 剖析。

典型 aps 字典对象包含以下三个属性:alert、badge 和 sound。例如,我们来看看以下输出内容:

applicationLaunchNotification = 0;
applicationStateActive = 0;
aps = {
alert = {
“action-loc-key” = Play;
body = “Your turn!”;
“launch-image” = “mysplash.png”;
};
badge = 5;
sound = “notification-beep.wav”;
};
messageFrom = Holly;
timestamp = “1350416054.782263″;

任何自定义声音或启动图像均必须包含在 XCode 项目的资源文件夹中。例如,在下面的图像中,我指定了notification-beep.wav 和 mysplash.png,并以此指代该服务器发送的推送通知。

图 6. 指定自定义声音和图像。

服务器端代码处理

下面是一个代码示例,您可以用它启动服务器端解决方案以处理设备令牌注册,现在我调用应用程序示例,展示您可能希望与第三方服务器开展通信的方式和时机,以便在从 Apple 接收设备令牌后存储设备令牌。目前,系统除显示令牌和消息收到之外,并没有对令牌执行任何操作。接下来,我们需要将用户的设备令牌及其他所有信息存储在数据库中,以备日后使用。

var http = require(‘http’);
var apn = require(‘apn’);
var qs = require(‘querystring’);

var server = http.createServer(function (req, res) {
if(req.method === “POST”) {
var fullBody=””;

req.on(‘data’, function(chunk)
{
fullBody += chunk;
console.log(“Full body ” + fullBody);
});

req.on(‘end’, function()
{
var data = qs.parse(fullBody);
console.log(“Token ” +data.token);
console.log(“Message ” + data.message);
var myDevice = new apn.Device(data.token);
// Now we need to store it! Add code to interface with a db
below…

res.writeHead(200, {“Content-Type”: “text/plain”});
res.end(“Thank you for registering\n”);
res.end();
});
}
}).listen(8888);
console.log(“Server running at http://127.0.0.1:”+server.address().port);

我只需要在本地主机上使用 Node.js 运行此脚本。当从实际设备执行测试时(因为模拟器中不支持推送通知),您可以在设备的 Wi-Fi 设置中设置 Manual HTTP Proxy,使其指向您计算机的 IP 地址。转到您的 Wi-Fi 网络,滚动到设置底部以设置 Manual Proxy 服务器和端口。下面是我提供的一个示例:

图 7. 在您的设备上执行测试。

通过 Argon (Node.js API) 发送通知

下面是一个简单代码示例,用于显示如何使用 argon 开源 Node.js API 向用户设备发送推送通知。我只需要对设备令牌执行硬编码即可进行快速测试,但*终您将需要从数据库检索它们,以便用于发送推送通知。

var http = require(‘http’);
var apn = require(‘apn’);
var url = require(‘url’);

var myPhone = “d2d8d2a652148a5cea89d827d23eee0d34447722a2e7defe72fe19d733697fb0”;
var myiPad = “51798aaef34f439bbb57d6e668c5c5a780049dae840a0a3626453cd4922bc7ac”;

var myDevice = new apn.Device(myPhone);

var note = new apn.Notification();
note.badge = 1;
note.sound = “notification-beep.wav”;
note.alert = { “body” : “Your turn!”, “action-loc-key” : “Play” , “launch-image” : “mysplash.png”};
note.payload = {‘messageFrom’: ‘Holly’};

note.device = myDevice;

var callback = function(errorNum, notification){
console.log(‘Error is: %s’, errorNum);
console.log(“Note ” + notification);
}
var options = {
gateway: ‘gateway.sandbox.push.apple.com’, // this URL is different for Apple’s Production Servers and changes when you go to production
errorCallback: callback,
cert: ‘PushNotificationSampleCert.pem’,
key:  ‘PushNotificationSampleKey.pem’,
passphrase: ‘myPassword’,
port: 2195,
enhanced: true,
cacheLength: 100
}
var apnsConnection = new apn.Connection(options);
apnsConnection.sendNotification(note);

上面的代码用于生成通知,在设备上如下所示,假设您已将设备的 Settings > Notifications > MyAppName 设置为 Alerts 选项:

图 8. 您设备上的警报通知。

如果您将应用程序上的 Alert Style 设备设置设定为 Banners,它将显示如下:

图 9. 您设备上的横幅通知。

重要提示:您必须将 PEM 文件更改为您在安装期间创建的证书和私有密钥(您*终按照 SSL 证书和配置部分的说明合并到单一 PEM 文件的内容)。请记住,首先将 CER 转换为 PEM,然后将 .p12 转换为 PEM。这些就是您此刻所需的两个文件。有关 argon 参数的详细信息,请参阅 argon readme 文件。在我的示例中,PEM 文件位于 Node.js 代码所在的文件夹中。如果您并未为它们设置密码,则可以忽略密码属性。

下一步阅读方向

我已经在 GitHub 上包含了一个针对参考应用程序创建的示例项目链接,因为其中包含我上面讨论的所有内容。我不建议使用这个现成项目,因为您必须在项目中设置自己独特的 App ID 和配置文件。*好从头开始创建自己的项目,仅将这个示例作为参考。我创建这个项目旨在*终跨平台使用 cordova 客户端工具,如我的文章(瞬间创建跨平台 PhoneGap (aka Cordova) 项目模板!)中所述,但目前仅创建了 iOS。因此,请在特定的 iOS 代码中引用 PGPushNotificationSample/platforms/ios 路径。您将会在PGPushNotificationSample/platforms/ios/www/js/index.js 文件中找到所有 JavaScript 函数。

ios中模拟手势单击或是双击

1.拓展UITouch类和UIEvent类(通过category),具体见附件TouchSynthesis.h和TouchSynthesis.m

2.在需要的类中,定义UITouch和UIEvent类的对象。

UITouch *touch = [[UITouchalloc] initWithPoint:point andView:mapview];

     UIEvent *eventDown = [[UIEventalloc] initWithTouch:touch];

[touch.view touchesBegan:[eventDownallTouches]  withEvent:eventDown];

[touch setPhase:UITouchPhaseEnded];

    UIEvent *eventUp = [[UIEventalloc] initWithTouch:touch];

    [touch.view touchesEnded:[eventUp allTouches] withEvent:eventUp];

    [eventDown release];

    [eventUp release];

     [touch release];

TouchSynthesis.h文件

#import <UIKit/UIKit.h>

@interface UITouch (Synthesize)

– (id)initInView:(UIView *)view;
-(id) initdoubletap:(UIView *)view;
– (id)initWithPoint:(CGPoint)point andView:(UIView*)view;
– (void)setPhase:(UITouchPhase)phase;
– (void)setLocationInWindow:(CGPoint)location;

@end

@interface UIEvent (Synthesize)

– (id)initWithTouch:(UITouch *)touch;

@end

TouchSynthesis.m文件

#import “TouchSynthesis.h”
#import “MyUITouch.h”

@implementation UITouch (Synthesize)

//
// initInView:phase:
//
// Creats a UITouch, centered on the specified view, in the view’s window.
// Sets the phase as specified.
//
– (id)initInView:(UIView *)view
{
NSLog(@”init in view”);
self = [super init];
if (self != nil)
{
CGRect frameInWindow;
if ([view isKindOfClass:[UIWindow class]])
{
frameInWindow = view.frame;
}
else
{
frameInWindow =
[view.window convertRect:view.frame fromView:view.superview];
}

_tapCount = 1;
_locationInWindow =
CGPointMake(
frameInWindow.origin.x + 0.5 * frameInWindow.size.width,
frameInWindow.origin.y + 0.5 * frameInWindow.size.height);
_previousLocationInWindow = _locationInWindow;

UIView *target = [view.window hitTest:_locationInWindow withEvent:nil];

_window = [view.window retain];
_view = [target retain];
_phase = UITouchPhaseBegan;
_touchFlags._firstTouchForView = 1;
_touchFlags._isTap = 1;
_timestamp = [NSDate timeIntervalSinceReferenceDate];
}
return self;
}
– (id)initdoubletap:(UIView *)view
{
NSLog(@”init in view”);
self = [super init];
if (self != nil)
{
CGRect frameInWindow;
if ([view isKindOfClass:[UIWindow class]])
{
frameInWindow = view.frame;
}
else
{
frameInWindow =
[view.window convertRect:view.frame fromView:view.superview];
}

_tapCount = 2;
_locationInWindow =
CGPointMake(
frameInWindow.origin.x + 0.5 * frameInWindow.size.width,
frameInWindow.origin.y + 0.5 * frameInWindow.size.height);
_previousLocationInWindow = _locationInWindow;

UIView *target = [view.window hitTest:_locationInWindow withEvent:nil];

_window = [view.window retain];
_view = [target retain];
_phase = UITouchPhaseBegan;
_touchFlags._firstTouchForView = 1;
_touchFlags._isTap = 1;
_timestamp = [NSDate timeIntervalSinceReferenceDate];
}
return self;
}

– (id)initWithPoint:(CGPoint)point andView:(UIView*)view
{
self = [super init];
if (self != nil)
{
CGRect frameInWindow;
if ([view isKindOfClass:[UIWindow class]])
{
frameInWindow = view.frame;
}
else
{
frameInWindow =
[view.window convertRect:view.frame fromView:view.superview];
}

_tapCount = 1;
_locationInWindow = point;
_previousLocationInWindow = _locationInWindow;
UIView *target = [view.window hitTest:_locationInWindow withEvent:nil];
_view = [target retain];
_window = [view.window retain];
_phase = UITouchPhaseBegan;
_touchFlags._firstTouchForView = 1;
_touchFlags._isTap = 1;
_timestamp = [NSDate timeIntervalSinceReferenceDate];
}
return self;
}
//
// setPhase:
//
// Setter to allow access to the _phase member.
//
– (void)setPhase:(UITouchPhase)phase
{
_phase = phase;
_timestamp = [NSDate timeIntervalSinceReferenceDate];
}

//
// setPhase:
//
// Setter to allow access to the _locationInWindow member.
//
– (void)setLocationInWindow:(CGPoint)location
{
_previousLocationInWindow = _locationInWindow;
_locationInWindow = location;
_timestamp = [NSDate timeIntervalSinceReferenceDate];
}

@end

//
// GSEvent is an undeclared object. We don’t need to use it ourselves but some
// Apple APIs (UIScrollView in particular) require the x and y fields to be present.
//
@interface GSEventProxy : NSObject
{
@public
unsigned int flags;
unsigned int type;
unsigned int ignored1;
float x1;
float y1;
float x2;
float y2;
unsigned int ignored2[10];
unsigned int ignored3[7];
float sizeX;
float sizeY;
float x3;
float y3;
unsigned int ignored4[3];
}
@end
@implementation GSEventProxy
@end

//
// PublicEvent
//
// A dummy class used to gain access to UIEvent’s private member variables.
// If UIEvent changes at all, this will break.
//
@interface PublicEvent : NSObject
{
@public
GSEventProxy           *_event;
NSTimeInterval          _timestamp;
NSMutableSet           *_touches;
CFMutableDictionaryRef  _keyedTouches;
}
@end

@implementation PublicEvent
@end

@interface UIEvent (Creation)

– (id)_initWithEvent:(GSEventProxy *)fp8 touches:(id)fp12;

@end

//
// UIEvent (Synthesize)
//
// A category to allow creation of a touch event.
//
@implementation UIEvent (Synthesize)

– (id)initWithTouch:(UITouch *)touch
{
CGPoint location = [touch locationInView:touch.window];
GSEventProxy *gsEventProxy = [[GSEventProxy alloc] init];
gsEventProxy->x1 = location.x;
gsEventProxy->y1 = location.y;
gsEventProxy->x2 = location.x;
gsEventProxy->y2 = location.y;
gsEventProxy->x3 = location.x;
gsEventProxy->y3 = location.y;
gsEventProxy->sizeX = 1.0;
gsEventProxy->sizeY = 1.0;
gsEventProxy->flags = ([touch phase] == UITouchPhaseEnded) ? 0x1010180 : 0x3010180;
gsEventProxy->type = 3001;

//
// On SDK versions 3.0 and greater, we need to reallocate as a
// UITouchesEvent.
//
Class touchesEventClass = objc_getClass(“UITouchesEvent”);
if (touchesEventClass && ![[self class] isEqual:touchesEventClass])
{
[self release];
self = [touchesEventClass alloc];
}

self = [self _initWithEvent:gsEventProxy touches:[NSSet setWithObject:touch]];
if (self != nil)
{
}
return self;
}

@end

MyUITouch.h文件
#import <Foundation/Foundation.h>

#ifdef __IPHONE_6_0
@interface UITouch () {
NSTimeInterval _timestamp;
UITouchPhase _phase;
UITouchPhase _savedPhase;
NSUInteger _tapCount;

UIWindow *_window;
UIView *_view;
UIView *_gestureView;
UIView *_warpedIntoView;
NSMutableArray *_gestureRecognizers;
NSMutableArray *_forwardingRecord;

CGPoint _locationInWindow;
CGPoint _previousLocationInWindow;
UInt8 _pathIndex;
UInt8 _pathIdentity;
float _pathMajorRadius;
struct {
unsigned int _firstTouchForView:1;
unsigned int _isTap:1;
unsigned int _isDelayed:1;
unsigned int _sentTouchesEnded:1;
unsigned int _abandonForwardingRecord:1;
} _touchFlags;
}
@end
#endif

iOS面试问题

准备技术方面的面试:
在直接切入问题之前,我们先讨论下一些基本的要领来确保你的技术面试尽可能顺利进行。
为每个可能出现的问题准备好答案是不可能的。所以需要更加关注基础方面的内容。确保你对Objective-C 2.0的特性都非常熟悉。可以猜的到会有一些关于通知(messaging),协议(protocols),动态类型(dynamic types),转发(forwarding),分类(categories),posing, method swizzling等方面的问题。面试者想考察你对现有的或者是之前出现的问题了解有多少。花几个小时去 StackOverflow 网站上看下*近经常提问到有关iOS方面的问题会对你有很大帮助。
读一遍 Apple’s Objective-C guides,确保你没有任何觉得比较薄弱的主题。像google式问法的那种问题,比如说一个小车需要多少个高尔夫球才能填满(250,000),或是在旧金山有多少扇窗户(大于10亿),现在大部分公司都停止问了。当你要面对这些类型的问题的时候,你的思路比你的答案要更重要,关于这个问题你是如何思考的 – 这才是面试官关心的问题。
准备好在白板上编码
如果你是面对面的面试,他们可能希望你在白板上直接编程。确保在你面试之前做了一些练习,因为在一群人面前直接编写代码会非常有压力,没有代码自动补全功能的编码难度远远大于你的想象。
为你在简历上写的熟悉的编程语言做好在白板上写代码的准备。我的一个朋友在面试中被要求在白板上用Erlang来编程,Erlang是他在简历中列出来的编程语言。他得到了那份工作。地球上知道Erlang的仅有三个人,我确定他是其中的一个。
面试*节
如果是进行面对面面试,先询问下公司的着装要求。如果面试官穿短裤T恤,而你穿着西装,这样就会比较尴尬,而且面试官也可能会很不愉快。如果你穿球衣而其他人穿西装的话也会是同样的结果。关于这点,可以事先询问招聘经理,他会很乐意给你一些相关建议。
确保手机调成静音。如果你知道我在面试的时候听到过多少次电话响起的声音,你一定会惊讶的。大多数情况下你都不应该在面试中接电话或者查看下你的手机。如果有一些潜在的紧急情况,例如你的妻子马上要分娩或者是你的丈夫正在做手术,请提前告诉你的招聘经理,这样的话你接电话的行为还可以被接受。
在面试过程中,无论是身体还是精神都需要放轻松。尽量把面试时间定到一段你相对空闲的时间(之后你不会有其他的事情需要做)。如果你把面试定到你目前工作的午休时间,那肯定不会达到*好的效果。有时我甚至需要缩短面试时间就只因为面试者的现任老板需要他去工作! 请避免增加你目前已有的压力。
进行面对面的面试,请早到15分钟左右,但不要太早。对于电话面试,如果是在线会议的话,确保提前两分钟拨号进入。直接打电话来的,确保能按时准备好。
准备好问题
在面试的结尾,面试官通常会问你关于公司和工作,你还有哪些问题。请事先准备好你的问题,把你想要问的问题写到纸上。这会表明你对这份工作真的感兴趣而不是仅仅走走过场。很多面试者在这个环节中都不会问任何内容,这让我感到很惊讶。如果你觉得这个工作适合你的话,这是一个了解公司的很好的机会。
面试题目
你期待已久的内容到了 – 题目!
我们的技术性面试通常持续1个小时。有一张包含75个问题的表单,刚开始我会从里面随机抽取题目。之后我根据对候选人知识方面的了解,有选择的缩小问题的范围。例如,如果我怀疑候选人哪块儿有薄弱的知识点,我会继续深入的问那块儿内容。
这篇文章发表之后,我*爱问的问题和我首选的问题将会被淘汰了。而我的*个问题将会是:你读过这篇文章吗?
当回答这些问题的时候,尽量使你的答案简明扼要,如果必要的话解释下你的思路。面试官不是因为不知道答案而来问你这些问题的,他们要知道的是你对你所说的内容了解程度有多少。
请注意,我只会列出问题,没有答案。你需要去回答,如果你还不是很了解这些内容的话, 记住学习的过程是*富有乐趣的一个过程! 如果你找到答案的话,你可以随意的在论坛上进行分享。
直接进入正题,这些是技术性面试的一些样例题目。
请解释下method swizzling,并说出你一般什么时候会用到它?- 我喜欢问这个问题因为这属于较为深层次的语法。大多数人都没有使用swizzling的需求(言外之意会用到swizzling的一般开发过一些核心的内容了)。而且通过开发者关于这个问题的回答,我还可以了解他们对复杂代码的执行有多大程度上的约束。一个人如果说他 swizzle所有的代码,那比那些说从来没用过swizzle的人更可怕。(译者注:了解更多  method swizzling
假设有三个对象,一个父类的父类,一个父类和一个子类。父类的父类持有父类的引用(retain),父类持有子类的引用(retain),子类持有父类的引用(retain)。父类的父类释放(release)父类,解释下会发生什么。 -——即使有ARC,我依然喜欢问一些内存相关的问题,这显示了这个人有一定时间的开发经验,而且明白核心的框架是如何运作的。
当一个空指针(nil pointer)调用了一个方法会发生什么?——了解处理基础的Objective-C相关问题是很重要的,有好多次我都听到了错误的回答,这很令我震惊。
为什么retainCount*对不能用在发布的代码中?请给出两个相对独立的解释。—— 考察这个问题会有两个好处:一是可以确定面试者目前确实没有使用retainCount,并且看看他们是否知道为什么他们不应该使用。
请说明一下你查找或者解决内存泄露的处理过程。这个可以深入了解面试者对内存管理方面的知识,instruments的运用及其调试的处理过程。——有时候我会听到一些可怕的回答:“注释掉部分代码直到内存泄露问题被修复”。
解释下自动回收池(autorelease pool)在程序运行时是如何运作的。 -——这类型的问题已经超出代码基础了,一个程序员只有阅读过一部分开发类书籍才能学到这些内容。这些问题也同样能考察他对程序底层代码运作的了解程度。
当处理属性申明的时候,原子(atomic)跟 非原子(non-atomic)属性有什么区别?-——好多人都不知道这个问题的答案,我又一次震惊了。很多人他们都是看别人是怎么声明的,他们就怎么来声明。类似这种的题目会暴漏出来很多问题。
在C语言中,你如何能用尽可能短的时间来倒转一个字符串?—— 我不大喜欢深入问计算机的核心内容, 但是通过这个问题可以让我了解到他们是如何思考的,同样也可以了解到他们的C语言背景。深入询问时间复杂度(big O notation)也能让我了解面试者的水平。
遍历一个NSArray和一个NSSet,哪一个更快? ——另一个深入的提问。有时候一个类解决了问题并不能代表你就应该用这个类。
解释代码签名(code signing)是如何运作的。 —— 很多候选人都完全不了解代码签名是如何运作的,然后抱怨说他们一直被一些代码签名的一些问题所困扰。
Objective-C中的posing指的是什么? —— Posing是一个Object-C的小众语法特性。像 swizzling那个问题一样,这个问题可以让我了解面试者对语言的深入程度。
列举标准Xcode版本中的6个工具。 —— 通过这个问题我可以大致的了解到面试者会在这些工具上花费多少时间。提示:至少得用10%的写代码的时间来用这些工具。
copy跟retain有什么区别? —— *近好多开发者都开始用ARC了,内存方面的问题就更能反映出一个开发者的知识水平了。
frames跟bounds有哪些区别? -——我不会问很多界面相关 (GUI-type)的问题,我应该问的多一些,不过通过这个问题我差不多能了解到一个开发者做了多少界面工作。
执行如下的代码会发生什么情况?
  1. Ball *ball = [[[[Ball alloc] init] autorelease] autorelease];
另一个内存相关的问题,这个问题的答案不能单用会崩溃来回答,我想要知道为什么崩溃,何时会崩溃。
列举5个iOS app的状态。—— 几乎没有人能正确的回答出这个问题,通常我会给出一个例子,诸如后台运行的状态(background state),这样他们就知道我在说的是那块儿内容了。
你认为这次面试能很好的体现出来你作为开发者的能力么?—— 一些人说可以测试的很好,但是有些人不这么认为。我倾向于给面试者一些表达他们自己想法的机会。自信是非常重要的品质,而对应这个问题的回答也能很好的反应出一个人的自信程度。
我在提问这些问题的时候顺带会附加一些问题,类似“为什么会发生这种状况?”或者是“请解释下你的解题思路”。技术性面试的关键取决于面试者对语言跟平台方面了解的程度,这不仅仅包含技术的广度,还有技术的深度。
实际编码的面试
这是我们*重要的面试,这场面试可以直接反映出面试者是否可以胜任工作。我们将提供给面试者一个名为 The Dragon’s Test的app,目前已知这个app有很多问题。然后给面试者一个bug清单,根据面试者解决问题的能力和时间来评定面试者的等级。
我们公司给一些大的企业法人提供iOS开发服务,我们旨在用*快速的转换模式来给客户提供*可靠的结果。所以实际编码的面试是有效评估面试者开发能力的重要面试, 因为它能让我确定在公司盈利的前提下,应该支付给这个面试者多少薪水。对软件面试本身来说,能找出快速解决问题的开发者就是*大的幸事。
在完成细节跟完成时间之间,有一个微妙的平衡点。如果有个人用1/3的时间完成了95%,另一个人用了更多的时间完成了100%的话,那我倾向于选择前者。还有一个秘密可以告诉你,我们也是坚持通过这种实际编码的测试来选择员工主管的。
幸运的是(或者也可以说这是不幸的,取决于你是如何看待这个问题的),准备实际编码的面试的*好的方式就是勤练习。你做的app越多,你越有可能更快的开发出更稳健的代码。所以要坚持练习和学习!
该何去何从?
 
总结一下:
请熟练掌握计算机语言的基础知识,这样可以让你帮助你在面试中放松自己。在面试中,谈论你要应聘的公司跟公司旗下的产品。始终保持面试答案简明扼要、直奔主题。
在做编码工作的时候,保持头脑的快速运转。你完成任务的速度会决定项目的成败。如果你能更快速的编写好优秀的代码,那你就更有价值,你更有价值,公司就更愿意给你更多的薪水。
Ray 和我都希望你喜欢这个系列的文章!如果你喜欢看更多同类型的文章 – 比如说讨论作为一个iOS开发者你要如何提升你的技能,怎样找到iOS的工作,或者作为iOS开发者你应该期望自己拿多少薪水。如果你喜欢看到这些内容,请让我们知道哦。
另外说一句,你知道我上面提出的那些iOS面试问题的答案么?如果知道的话,加入我们的论坛讨论组,对比下你的答案!

iOS 13疯狂弹窗,附两种解决办法,iOS13.1版本验证已关闭

iOS 13系统在今天凌晨疯狂弹窗,这影响了不少用户使用。从用户的反馈来看,这次iOS 13的弹窗影响范围非常的广,而弹窗的信息是:“The iTunes Store is unable to process purchases at this time. Please try again later(iTunes Store目前无法执行购买请求。请稍后再试。)”

640?wx_fmt=png

除了国外用户外,从一些国内网友反馈的情况看,他们也遇到了这个情况。当然,这个问题显然并不只限于iOS 13才会发生,已经有用户发现在iOS 11和iOS 12也会弹出相同的弹窗,部分iPad机型也没能幸免。

  • 解决方法一:

1. 点击“设置”—打开“与App Store”点击id账号退出登录

2. 设置—通用—还原—还原网络设置—关机重启—断开Wifi—启用4G网络—重新登录id即可

不过有部分用户反映自己的手机通过以上的操作之后仍然还是出现弹窗的问题,那么我觉得下一种方法可能更适合你。

  • 解决方法二:

卸载iTunes Store即可解决,删除又清爽,又干净,心情也美美的,当然卸载完毕我们还能再次下载回来哦,所以我们也没必要太担心。

640?wx_fmt=png

目前,苹果还没有对此事进行说明,有遇到这个情况的粉丝吗,欢迎留言讨论。

640?wx_fmt=png

iOS13.1关闭验证

640?wx_fmt=png

640?wx_fmt=png

说重点:三天前,苹果公司正式关闭了 iOS12.4.1 、13.0 和 13.1.1 系统验证,唯独iOS 13.1没有关闭系统验证,为什么跳版本关闭,原因未知,但!今天,苹果公司正式关闭了iOS13.1系统,意味着你无法升降该系统版本,你只能刷iOS13.1.2系统。

解决iOS8安装企业版无反应问题

iOS7可以下载没有任何问题,iOS8发现挂在官网上的企业版的app点击了提示是否安装应用程序,但是确认以后没有反应,找了很久,都没有发现问题。后来查看了的device console发现安装的时候出现

<span style="font-size: 24px;"><code><span style="color: rgb(255, 0, 0);"><span class="typ">LoadExternalDownloadManifestOperation</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Ignore</span><span class="pln"> manifest download</span><span class="pun">,</span><span class="pln"> already have bundleID</span><span class="pun">:</span><span class="pln"> com</span><span class="pun">.</span><span class="pln">mycom</span><span class="pun">.</span><span class="typ">MyApp</span></span></code></span>

后来查资料外国开发者推测是iOS8的一个bug:

The biggest issue for us is that we can not reproduce this onany of our devices. Our suspicion is that iOS 8 has some internalcache with bundle IDs and just doesn’t install a build if it thinksthat an app with this bundle ID is already installed. As theinstallation doesn’t even start, we think that iOS is matching thebundle identifier from the manifest plist against this cache.

它会寻找是否ios缓存的identifier与bundle identifier在plist文件中匹配,如果匹配,它会认为已经安装了,就不会有反应。 上面解释的很清楚。所以解决办法就是在plist文件中修改bundle Identifier。

比如你的plist文件的BundleID是com.mycom.MyApp,则修改成com.mycom.MyApp.fixios8。(创建一个假的bundleID,可以随便取,这样ios就不会认为你已经安装。记住是修改plist文件的bundleID,不是应用程序的bundleID)

发布以后就发现可以了。只是如果你已经安装了app,则会出现一个新的下载的空白icon,因为这个app的bundleID与你plist的bundleID不一致,当下载完成后,会覆盖原本app,因为它会检测到下载安装的app的bundleID已经存在并且覆盖。

完美解决。