作者: xiao, yanzi

iphone屏幕镜像连电视_手机如何连接电视机?

一般情况下,手机想要直接的连接到电视机上是无法实现的,但是,我们如果只是想手机上的视频投影到电视机上播放还是没有问题的。我们可以通过DLNA技术来实现这个功能。

先解释一下DLNA

2b32ed1d424805d3fc88df492f78d7b0.pngDLNA其实严格来说并不是一种技术,而是一种解决方案,全程叫“DIGITAL LIVING NETWORK ALLIANCE(数字生活网络联盟)”,是由索尼、英特尔、微软等公司发起成立的。为的就是实现PC电脑、移动设备和消费电器在无线或者有线网络中的互联互通。

不过2017年1月15日,DLNA组织已经正式解散了,不过这个技术依旧被使用着。

怎么来实现投屏呢?

首先,我们需要一个联网的路由器(*好是无线),一部智能手机(iPhone和安卓都行),一台电视机。如果电视是互联网电视,能够直接连上无线网络,那么就不需要更多设备了,如果电视没有这个功能,那么你还需要一个小小的投屏设备。

我们先假设电视是互联网电视

对于iPhone手机来说,那就很简单了,先保证手机连上了你家里的wifi,然后保证你的电视机是连上wifi的。

然后打开手机,向上滑动出功能菜单,其中就有一个叫做屏幕镜像的功能。

8e8b60c1b3aca5cad8de4bba3134c12b.png7a92b788291950ff5b9750c12e76f643.png

点击以后,就能够看到你已经联网的电视机了。这是,点击选中,OK,一切就完成了,是不是很简单。

如果是安卓手机呢?华为的手机,很多是自带了投屏功能,和iPhone一样,可以直接投屏。如果是没有自带这个功能的安卓手机,你就需要安装一个投屏APP,类似的投屏APP非常多,到应用市场里面找一个就OK了。

d5f2b5943d6ba00a96b728a88c3bd088.png

使用的话,也就是打开APP,然后选择投屏,再选择设备就OK了,也非常简单。

当然,如果你是在用爱艺奇,youku等视频APP看视频,想要投屏到电视上,一般在播放视频的时候,手机屏幕的右上角会有类似的功能按钮,就可以实现投屏了。

77604225779c7f2a05136de449bb629b.png

如果我的电视不是互联网电视,不能联网怎么办呢?

那你就需要借助外力了。一般来说,小米盒子这种互联网机顶盒都是带有投屏功能的,如果你有,可以通过投屏到这些设备上,然后在电视上播放。

如果没有机顶盒,那么就只有买一个小设备了。选择设备的时候,可以根据自己的使用目的来购买。例如:你经常看爱奇艺的视频,那么你就可以选一个电视果。

fe4a2bc491ec9730acd94914981c32d4.png

非常小的个头,还送爱奇艺会员,并且,在投屏爱奇艺的视频时,其实并不是投屏,而是通过电视果直接播放。

是不是投屏有什么区别呢?

如果是投屏,手机关闭或者断网,那么电视也就不会继续播放了,因为电视是通过连接手机来播放的。但是电视果就好像一个机顶盒,如果是播放爱奇艺的视频,其实就不需要你手机作为信号源了,电视果可以直连爱奇艺视频网站进行播放。手机关机都不会受到影响。

当然,还有什么天猫魔盒、小米盒子等等很多选择。

前期回顾:

1:都说安卓手机用一两年就卡到不行,但知道这3招,同样可以用很久

2:iPhone深深隐藏的5个秘密开关,苹果官方都求着你去开,不开血亏

3:App Store里5个热门应用,款款都是黑科技,让你的苹果好用爆表!

ios屏蔽描述文件官方下载入口_iOS屏蔽更新描述文件失效解决办法:用这个方法屏蔽iOS13更新…

相信不少苹果设备的用户都经历过这样一个场景,只是睡一觉的时间,自己手中的iPhone或者iPad自动升级到了*新iOS版本。众所周知,由于iOS系统的机制,当设备开启“自动更新”,苹果设备会在适合的网络环境下自动下载*新的系统,且在充电状态+接入WI-FI的时候,自动升级新版iOS系统。

d9e9dc4dfd68cb4e5d5799b242a715de.png

对部分用户来说,他们希望能够停留在较低版本,而iPhone的升级提醒,却让人感到心烦,一旦误操作,就无法退回到已关闭验证的较早版本。在过去,我们都是利用苹果tvOS的描述文件来屏蔽iOS升级,在iOS设备上安装tvOS描述文件就可以让系统误以为检查的是tvOS的OTA更新,因此在iOS系统上就收不到更新。随着屏蔽系统更新的tvOS 12描述文件在今年1月底失效后,至今没有可用的屏蔽升级描述文件。为了避免系统意外升级,我们可以先通过其它的“曲线救国”方式来屏蔽升级。

  • 方法:关闭“设置“的网络权限

原理:因为系统升级需要联网下载新固件,关闭“设置”的网络权限,无法接入网络,所以也就不会自动下载*新固件,避免了意外升级。

使用方法:

1. 先打开“设置-iPhone存储空间”检查新固件是否已经被下载,如果系统固件已经下载,先将其删除;

2. 前往“设置-无线局域网-使用WLAN与蜂窝移动网的应用”,在列表中找到“设置”,将其权限关闭。

3. 关闭“设置”的网络权限后,我们就不用再担心新固件自动被下载到设备上。

7dcd342491b16fa1edc7861d2b6a6185.png

优点:简单,易操作,无需安装额外的配置文件或者App。

缺点:

1. 可能影响到其它需要联网才能设置的功能。

解决办法:可在需要使用“设置”联网时,重新打开网络权限,使用完成后重复上述步骤即可。

2. “设置”图标上的提醒数字“1”不会消失。

iOS开发中怎么样使用激光推送

1.注册激光推送的账号 —-> 创建应用

2.上传推送测试和发布的p12文件  注意密码的填写

3.下载sdk并拖进工程里

4.在build setting 搜索search   把路径改一下%title插图%num

%title插图%num

然后导入必须的库

CFNetwork.framework
CoreFoundation.framework
CoreTelephony.framework
SystemConfiguration.framework
CoreGraphics.framework
Foundation.framework
UIKit.framework
Security.framework
Xcode7需要的是libz.tbd;Xcode7以下版本是libz.dylib

配置plist文件

实现如下代码

AppDelegate.m
// 远程推送
//
// Created by  on 16/3/28.
// Copyright © 2016年 sjb. All rights reserved.
//
#import “AppDelegate.h”
#import “JPUSHService.h”

#define kJpushKey @”c171bc25d7754e085b48861b”
#define kMasterSecret (7f37465534cece94ac94c277)
static NSString *appKey = @”AppKey copied from JPush Portal application”;

static NSString *channel = @”Publish channel”;
static BOOL isProduction = FALSE;

@interface AppDelegate ()

@end

@implementation AppDelegate

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}

if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
[JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil];
}else{
[JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil];
}

[JPUSHService setupWithOption:launchOptions appKey:kJpushKey
channel:channel apsForProduction:isProduction];

return YES;
}

– (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

// Required
[JPUSHService registerDeviceToken:deviceToken];
}

– (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

// Required,For systems with less than or equal to iOS6
[JPUSHService handleRemoteNotification:userInfo];
}

– (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

// IOS 7 Support Required
[JPUSHService handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}

– (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {

//Optional
NSLog(@”did Fail To Register For Remote Notifications With Error: %@”, error);
}

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

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速