Related
org.acegisecurity.BadCredentialsException: org.springframework.security.authentication.BadCredentialsException: Bad credentials; nested exception is org.springframework.security.authentication.BadCredentialsException: Bad credentials
I'm not able save anything in configure system
Error
org.acegisecurity.BadCredentialsException: org.springframework.security.authentication.BadCredentialsException: Bad credentials; nested exception is org.springframework.security.authentication.BadCredentialsException: Bad credentials
org.springframework.security.authentication.BadCredentialsException: Bad credentials
at hudson.security.HudsonPrivateSecurityRealm.authenticate2(HudsonPrivateSecurityRealm.java:207)
at hudson.security.AbstractPasswordBasedSecurityRealm.doAuthenticate(AbstractPasswordBasedSecurityRealm.java:97)
at hudson.security.AbstractPasswordBasedSecurityRealm.access$000(AbstractPasswordBasedSecurityRealm.java:30)
at hudson.security.AbstractPasswordBasedSecurityRealm$Authenticator.retrieveUser(AbstractPasswordBasedSecurityRealm.java:181)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:133)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
at org.acegisecurity.AuthenticationManager.lambda$fromSpring$0(AuthenticationManager.java:38)
Caused: org.acegisecurity.BadCredentialsException: org.springframework.security.authentication.BadCredentialsException: Bad credentials; nested exception is org.springframework.security.authentication.BadCredentialsException: Bad credentials
at org.acegisecurity.BadCredentialsException.fromSpring(BadCredentialsException.java:56)
at org.acegisecurity.AuthenticationException.fromSpring(AuthenticationException.java:80)
at org.acegisecurity.AuthenticationManager.lambda$fromSpring$0(AuthenticationManager.java:40)
at hudson.plugins.skype.im.transport.SkypePublisherDescriptor.applyHudsonLoginPassword(SkypePublisherDescriptor.java:169)
at hudson.plugins.skype.im.transport.SkypePublisherDescriptor.configure(SkypePublisherDescriptor.java:341)
at jenkins.model.Jenkins.configureDescriptor(Jenkins.java:3859)
at jenkins.model.Jenkins.doConfigSubmit(Jenkins.java:3823)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:710)
at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:396)
at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:408)
at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:212)
at org.kohsuke.stapler.SelectionInterceptedFunction$Adapter.invoke(SelectionInterceptedFunction.java:36)
at org.kohsuke.stapler.verb.HttpVerbInterceptor.invoke(HttpVerbInterceptor.java:48)
at org.kohsuke.stapler.SelectionInterceptedFunction.bindAndInvoke(SelectionInterceptedFunction.java:26)
at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:145)
at org.kohsuke.stapler.MetaClass$11.doDispatch(MetaClass.java:536)
at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:766)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:694)
at org.kohsuke.stapler.Stapler.service(Stapler.java:240)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1626)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:154)
at org.jenkinsci.plugins.ssegateway.Endpoint$SSEListenChannelFilter.doFilter(Endpoint.java:248)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at jenkins.security.ResourceDomainFilter.doFilter(ResourceDomainFilter.java:76)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at jenkins.telemetry.impl.UserLanguages$AcceptLanguageFilter.doFilter(UserLanguages.java:129)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at com.atlassian.bitbucket.jenkins.internal.applink.oauth.serviceprovider.auth.OAuth1aRequestFilter.doFilter(OAuth1aRequestFilter.java:91)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at io.jenkins.blueocean.ResourceCacheControl.doFilter(ResourceCacheControl.java:134)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at io.jenkins.blueocean.auth.jwt.impl.JwtAuthenticationFilter.doFilter(JwtAuthenticationFilter.java:60)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:239)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:215)
at net.bull.javamelody.PluginMonitoringFilter.doFilter(PluginMonitoringFilter.java:88)
at org.jvnet.hudson.plugins.monitoring.HudsonMonitoringFilter.doFilter(HudsonMonitoringFilter.java:121)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at jenkins.metrics.impl.MetricsFilter.doFilter(MetricsFilter.java:125)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at hudson.plugins.locale.LocaleFilter.doFilter(LocaleFilter.java:42)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:157)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:153)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:92)
at jenkins.security.AcegiSecurityExceptionFilter.doFilter(AcegiSecurityExceptionFilter.java:52)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at hudson.security.UnwrapSecurityExceptionFilter.doFilter(UnwrapSecurityExceptionFilter.java:51)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:105)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:101)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:92)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:218)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at jenkins.security.BasicHeaderProcessor.doFilter(BasicHeaderProcessor.java:93)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:62)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:109)
at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:168)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:51)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:82)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at jenkins.security.SuspiciousRequestFilter.doFilter(SuspiciousRequestFilter.java:36)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1435)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1350)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:383)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:882)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1036)
at java.base/java.lang.Thread.run(Thread.java:834)
I got Configuration as Code version 1414.v878271fc496f installed.
I got the the error "A problem occurred while processing the request." when trying to apply an existing configuration. I tried to upgrade the plugin to a later version but it still does not work. Anyone knows what is causing the apply to fail? Thanks.
May 12, 2022 12:54:42 PM WARNING org.eclipse.jetty.server.handler.ContextHandler$Context log
Error while serving http://192.168.59.103:30581/configuration-as-code/replace
java.lang.NullPointerException
at hudson.model.MyViewsProperty.save(MyViewsProperty.java:139)
at hudson.BulkChange.commit(BulkChange.java:97)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:270)
at io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator.configure(DataBoundConfigurator.java:82)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$doConfigure$16668e2$1(HeteroDescribableConfigurator.java:277)
at io.vavr.CheckedFunction0.lambda$unchecked$52349c75$1(CheckedFunction0.java:247)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.doConfigure(HeteroDescribableConfigurator.java:277)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$null$2(HeteroDescribableConfigurator.java:86)
at io.vavr.control.Option.map(Option.java:392)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$configure$3(HeteroDescribableConfigurator.java:86)
at io.vavr.Tuple2.apply(Tuple2.java:238)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.configure(HeteroDescribableConfigurator.java:83)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.configure(HeteroDescribableConfigurator.java:55)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:344)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:275)
at io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator.configure(DataBoundConfigurator.java:82)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:344)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:275)
at io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator.configure(DataBoundConfigurator.java:82)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$doConfigure$16668e2$1(HeteroDescribableConfigurator.java:277)
at io.vavr.CheckedFunction0.lambda$unchecked$52349c75$1(CheckedFunction0.java:247)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.doConfigure(HeteroDescribableConfigurator.java:277)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$null$2(HeteroDescribableConfigurator.java:86)
at io.vavr.control.Option.map(Option.java:392)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$configure$3(HeteroDescribableConfigurator.java:86)
at io.vavr.Tuple2.apply(Tuple2.java:238)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.configure(HeteroDescribableConfigurator.java:83)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.check(HeteroDescribableConfigurator.java:92)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.check(HeteroDescribableConfigurator.java:55)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:350)
at io.jenkins.plugins.casc.BaseConfigurator.check(BaseConfigurator.java:286)
at io.jenkins.plugins.casc.ConfigurationAsCode.lambda$checkWith$8(ConfigurationAsCode.java:776)
at io.jenkins.plugins.casc.ConfigurationAsCode.invokeWith(ConfigurationAsCode.java:712)
at io.jenkins.plugins.casc.ConfigurationAsCode.checkWith(ConfigurationAsCode.java:776)
at io.jenkins.plugins.casc.ConfigurationAsCode.checkWith(ConfigurationAsCode.java:650)
at io.jenkins.plugins.casc.ConfigurationAsCode.canApplyFrom(ConfigurationAsCode.java:219)
at io.jenkins.plugins.casc.ConfigurationAsCode.doReplace(ConfigurationAsCode.java:196)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:710)
at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:393)
Caused: java.lang.reflect.InvocationTargetException
at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:397)
at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:405)
at org.kohsuke.stapler.interceptor.RequirePOST$Processor.invoke(RequirePOST.java:77)
at org.kohsuke.stapler.PreInvokeInterceptedFunction.invoke(PreInvokeInterceptedFunction.java:26)
at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:208)
at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:141)
at org.kohsuke.stapler.MetaClass$11.doDispatch(MetaClass.java:536)
at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:766)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
at org.kohsuke.stapler.MetaClass$9.dispatch(MetaClass.java:457)
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:766)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:694)
at org.kohsuke.stapler.Stapler.service(Stapler.java:240)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1626)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:156)
at jenkins.telemetry.impl.UserLanguages$AcceptLanguageFilter.doFilter(UserLanguages.java:128)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:153)
at jenkins.security.ResourceDomainFilter.doFilter(ResourceDomainFilter.java:80)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:153)
at jenkins.metrics.impl.MetricsFilter.doFilter(MetricsFilter.java:125)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:153)
at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:159)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:153)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:92)
at jenkins.security.AcegiSecurityExceptionFilter.doFilter(AcegiSecurityExceptionFilter.java:52)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at hudson.security.UnwrapSecurityExceptionFilter.doFilter(UnwrapSecurityExceptionFilter.java:53)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:121)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:105)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:101)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:92)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:218)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at jenkins.security.BasicHeaderProcessor.doFilter(BasicHeaderProcessor.java:97)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:62)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:109)
at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:171)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:51)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:85)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at jenkins.security.SuspiciousRequestFilter.doFilter(SuspiciousRequestFilter.java:39)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1434)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:386)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.base/java.lang.Thread.run(Thread.java:829)
May 12, 2022 12:54:42 PM WARNING hudson.init.impl.InstallUncaughtExceptionHandler handleException
Caught unhandled exception with ID 57901936-6d57-4f1b-9d2b-1cf3a8404e58
java.lang.NullPointerException
at hudson.model.MyViewsProperty.save(MyViewsProperty.java:139)
at hudson.BulkChange.commit(BulkChange.java:97)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:270)
at io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator.configure(DataBoundConfigurator.java:82)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$doConfigure$16668e2$1(HeteroDescribableConfigurator.java:277)
at io.vavr.CheckedFunction0.lambda$unchecked$52349c75$1(CheckedFunction0.java:247)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.doConfigure(HeteroDescribableConfigurator.java:277)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$null$2(HeteroDescribableConfigurator.java:86)
at io.vavr.control.Option.map(Option.java:392)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$configure$3(HeteroDescribableConfigurator.java:86)
at io.vavr.Tuple2.apply(Tuple2.java:238)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.configure(HeteroDescribableConfigurator.java:83)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.configure(HeteroDescribableConfigurator.java:55)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:344)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:275)
at io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator.configure(DataBoundConfigurator.java:82)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:344)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:275)
at io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator.configure(DataBoundConfigurator.java:82)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$doConfigure$16668e2$1(HeteroDescribableConfigurator.java:277)
at io.vavr.CheckedFunction0.lambda$unchecked$52349c75$1(CheckedFunction0.java:247)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.doConfigure(HeteroDescribableConfigurator.java:277)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$null$2(HeteroDescribableConfigurator.java:86)
at io.vavr.control.Option.map(Option.java:392)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.lambda$configure$3(HeteroDescribableConfigurator.java:86)
at io.vavr.Tuple2.apply(Tuple2.java:238)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.configure(HeteroDescribableConfigurator.java:83)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.check(HeteroDescribableConfigurator.java:92)
at io.jenkins.plugins.casc.impl.configurators.HeteroDescribableConfigurator.check(HeteroDescribableConfigurator.java:55)
at io.jenkins.plugins.casc.BaseConfigurator.configure(BaseConfigurator.java:350)
at io.jenkins.plugins.casc.BaseConfigurator.check(BaseConfigurator.java:286)
at io.jenkins.plugins.casc.ConfigurationAsCode.lambda$checkWith$8(ConfigurationAsCode.java:776)
at io.jenkins.plugins.casc.ConfigurationAsCode.invokeWith(ConfigurationAsCode.java:712)
at io.jenkins.plugins.casc.ConfigurationAsCode.checkWith(ConfigurationAsCode.java:776)
at io.jenkins.plugins.casc.ConfigurationAsCode.checkWith(ConfigurationAsCode.java:650)
at io.jenkins.plugins.casc.ConfigurationAsCode.canApplyFrom(ConfigurationAsCode.java:219)
at io.jenkins.plugins.casc.ConfigurationAsCode.doReplace(ConfigurationAsCode.java:196)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:710)
at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:393)
at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:405)
at org.kohsuke.stapler.interceptor.RequirePOST$Processor.invoke(RequirePOST.java:77)
at org.kohsuke.stapler.PreInvokeInterceptedFunction.invoke(PreInvokeInterceptedFunction.java:26)
at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:208)
at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:141)
at org.kohsuke.stapler.MetaClass$11.doDispatch(MetaClass.java:536)
at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:766)
Caused: javax.servlet.ServletException
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:816)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
at org.kohsuke.stapler.MetaClass$9.dispatch(MetaClass.java:457)
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:766)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:694)
at org.kohsuke.stapler.Stapler.service(Stapler.java:240)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1626)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:156)
at jenkins.telemetry.impl.UserLanguages$AcceptLanguageFilter.doFilter(UserLanguages.java:128)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:153)
at jenkins.security.ResourceDomainFilter.doFilter(ResourceDomainFilter.java:80)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:153)
at jenkins.metrics.impl.MetricsFilter.doFilter(MetricsFilter.java:125)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:153)
at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:159)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:153)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:92)
at jenkins.security.AcegiSecurityExceptionFilter.doFilter(AcegiSecurityExceptionFilter.java:52)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at hudson.security.UnwrapSecurityExceptionFilter.doFilter(UnwrapSecurityExceptionFilter.java:53)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:121)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:105)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:101)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:92)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:218)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at jenkins.security.BasicHeaderProcessor.doFilter(BasicHeaderProcessor.java:97)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:62)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:97)
at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:109)
at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:171)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:51)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:85)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at jenkins.security.SuspiciousRequestFilter.doFilter(SuspiciousRequestFilter.java:39)
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1434)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:386)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.base/java.lang.Thread.run(Thread.java:829)
I have an app that reads in the user's contact list, but I need to convert each number to the International Equivalent with the Country Code. For example, if a number is 07777777777, then the result would be +447777777777, or if a number was from Turkey and it was 0090, it would replace it with +90.
- (NSString *)ConvertNumberToInternational:(NSString *)number {
if(number != nil) {
if(number.length > 0) {
NSLocale *locale = [NSLocale currentLocale];
NSString *countryCode = [locale objectForKey: NSLocaleCountryCode];
NSDictionary *dict = [self dictCountryCodes];
number = [number stringByReplacingOccurrencesOfString:#" " withString:#""];
if([[number substringToIndex:1] isEqualToString:#"0"] && ![[number substringToIndex:2] isEqualToString:#"00"]) {
number = [NSString stringWithFormat:#"+44%#", [number stringByReplacingCharactersInRange:[number rangeOfString:#"0"] withString:#""]];
}
if([[number substringToIndex:2] isEqualToString:#"00"]) {
number = [NSString stringWithFormat:#"+%#%#", [dict objectForKey:countryCode], [number substringFromIndex:2]];
}
number = [number stringByReplacingOccurrencesOfString:#" " withString:#""];
}
}
return number;
}
-(NSDictionary *)dictCountryCodes{
NSDictionary *dictCodes = [NSDictionary dictionaryWithObjectsAndKeys:
#"93", #"AF",#"20",#"EG", #"355", #"AL", #"213", #"DZ", #"1", #"AS",
#"376", #"AD", #"244", #"AO", #"1", #"AI", #"1", #"AG",
#"54", #"AR", #"374", #"AM", #"297", #"AW", #"61", #"AU",
#"43", #"AT", #"994", #"AZ", #"1", #"BS", #"973", #"BH",
#"880", #"BD", #"1", #"BB", #"375", #"BY", #"32", #"BE",
#"501", #"BZ", #"229", #"BJ", #"1", #"BM", #"975", #"BT",
#"387", #"BA", #"267", #"BW", #"55", #"BR", #"246", #"IO",
#"359", #"BG", #"226", #"BF", #"257", #"BI", #"855", #"KH",
#"237", #"CM", #"1", #"CA", #"238", #"CV", #"345", #"KY",
#"236", #"CF", #"235", #"TD", #"56", #"CL", #"86", #"CN",
#"61", #"CX", #"57", #"CO", #"269", #"KM", #"242", #"CG",
#"682", #"CK", #"506", #"CR", #"385", #"HR", #"53", #"CU",
#"537", #"CY", #"420", #"CZ", #"45", #"DK", #"253", #"DJ",
#"1", #"DM", #"1", #"DO", #"593", #"EC", #"20", #"EG",
#"503", #"SV", #"240", #"GQ", #"291", #"ER", #"372", #"EE",
#"251", #"ET", #"298", #"FO", #"679", #"FJ", #"358", #"FI",
#"33", #"FR", #"594", #"GF", #"689", #"PF", #"241", #"GA",
#"220", #"GM", #"995", #"GE", #"49", #"DE", #"233", #"GH",
#"350", #"GI", #"30", #"GR", #"299", #"GL", #"1", #"GD",
#"590", #"GP", #"1", #"GU", #"502", #"GT", #"224", #"GN",
#"245", #"GW", #"595", #"GY", #"509", #"HT", #"504", #"HN",
#"36", #"HU", #"354", #"IS", #"91", #"IN", #"62", #"ID",
#"964", #"IQ", #"353", #"IE", #"972", #"IL", #"39", #"IT",
#"1", #"JM", #"81", #"JP", #"962", #"JO", #"77", #"KZ",
#"254", #"KE", #"686", #"KI", #"965", #"KW", #"996", #"KG",
#"371", #"LV", #"961", #"LB", #"266", #"LS", #"231", #"LR",
#"423", #"LI", #"370", #"LT", #"352", #"LU", #"261", #"MG",
#"265", #"MW", #"60", #"MY", #"960", #"MV", #"223", #"ML",
#"356", #"MT", #"692", #"MH", #"596", #"MQ", #"222", #"MR",
#"230", #"MU", #"262", #"YT", #"52", #"MX", #"377", #"MC",
#"976", #"MN", #"382", #"ME", #"1", #"MS", #"212", #"MA",
#"95", #"MM", #"264", #"NA", #"674", #"NR", #"977", #"NP",
#"31", #"NL", #"599", #"AN", #"687", #"NC", #"64", #"NZ",
#"505", #"NI", #"227", #"NE", #"234", #"NG", #"683", #"NU",
#"672", #"NF", #"1", #"MP", #"47", #"NO", #"968", #"OM",
#"92", #"PK", #"680", #"PW", #"507", #"PA", #"675", #"PG",
#"595", #"PY", #"51", #"PE", #"63", #"PH", #"48", #"PL",
#"351", #"PT", #"1", #"PR", #"974", #"QA", #"40", #"RO",
#"250", #"RW", #"685", #"WS", #"378", #"SM", #"966", #"SA",
#"221", #"SN", #"381", #"RS", #"248", #"SC", #"232", #"SL",
#"65", #"SG", #"421", #"SK", #"386", #"SI", #"677", #"SB",
#"27", #"ZA", #"500", #"GS", #"34", #"ES", #"94", #"LK",
#"249", #"SD", #"597", #"SR", #"268", #"SZ", #"46", #"SE",
#"41", #"CH", #"992", #"TJ", #"66", #"TH", #"228", #"TG",
#"690", #"TK", #"676", #"TO", #"1", #"TT", #"216", #"TN",
#"90", #"TR", #"993", #"TM", #"1", #"TC", #"688", #"TV",
#"256", #"UG", #"380", #"UA", #"971", #"AE", #"44", #"GB",
#"1", #"US", #"598", #"UY", #"998", #"UZ", #"678", #"VU",
#"681", #"WF", #"967", #"YE", #"260", #"ZM", #"263", #"ZW",
#"591", #"BO", #"673", #"BN", #"61", #"CC", #"243", #"CD",
#"225", #"CI", #"500", #"FK", #"44", #"GG", #"379", #"VA",
#"852", #"HK", #"98", #"IR", #"44", #"IM", #"44", #"JE",
#"850", #"KP", #"82", #"KR", #"856", #"LA", #"218", #"LY",
#"853", #"MO", #"389", #"MK", #"691", #"FM", #"373", #"MD",
#"258", #"MZ", #"970", #"PS", #"872", #"PN", #"262", #"RE",
#"7", #"RU", #"590", #"BL", #"290", #"SH", #"1", #"KN",
#"1", #"LC", #"590", #"MF", #"508", #"PM", #"1", #"VC",
#"239", #"ST", #"252", #"SO", #"47", #"SJ", #"963", #"SY",
#"886", #"TW", #"255", #"TZ", #"670", #"TL", #"58", #"VE",
#"84", #"VN", #"1", #"VG", #"1", #"VI", nil];
return dictCodes;
}
The above code does not work, as I am just using the user's current locale. I need to know the locale of the phone number. Any help would be appreciated!
so you assume just 0 is the iphone region always and 00 is the international number 'prefix' –
#import <Foundation/Foundation.h>
#interface T : NSObject
#end
#implementation T
- (NSString *)convertNumberToInternational:(NSString *)number {
if(number != nil) {
if(number.length > 0) {
NSLocale *locale = [NSLocale currentLocale];
NSString *countryCode = [locale objectForKey: NSLocaleCountryCode];
NSDictionary *dict = [self dictCountryCodes];
NSString *localNumberCode = dict[countryCode];
number = [number stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if([[number substringToIndex:1] isEqualToString:#"0"] && ![[number substringToIndex:2] isEqualToString:#"00"]) {
number = [NSString stringWithFormat:#"+%#%#", localNumberCode, [number substringFromIndex:1]];
}
else if([[number substringToIndex:2] isEqualToString:#"00"]) {
number = [NSString stringWithFormat:#"+%#", [number substringFromIndex:2]];
}
}
}
return number;
}
-(NSDictionary *)dictCountryCodes{
NSDictionary *dictCodes = [NSDictionary dictionaryWithObjectsAndKeys:
#"93", #"AF",#"20",#"EG", #"355", #"AL", #"213", #"DZ", #"1", #"AS",
#"376", #"AD", #"244", #"AO", #"1", #"AI", #"1", #"AG",
#"54", #"AR", #"374", #"AM", #"297", #"AW", #"61", #"AU",
#"43", #"AT", #"994", #"AZ", #"1", #"BS", #"973", #"BH",
#"880", #"BD", #"1", #"BB", #"375", #"BY", #"32", #"BE",
#"501", #"BZ", #"229", #"BJ", #"1", #"BM", #"975", #"BT",
#"387", #"BA", #"267", #"BW", #"55", #"BR", #"246", #"IO",
#"359", #"BG", #"226", #"BF", #"257", #"BI", #"855", #"KH",
#"237", #"CM", #"1", #"CA", #"238", #"CV", #"345", #"KY",
#"236", #"CF", #"235", #"TD", #"56", #"CL", #"86", #"CN",
#"61", #"CX", #"57", #"CO", #"269", #"KM", #"242", #"CG",
#"682", #"CK", #"506", #"CR", #"385", #"HR", #"53", #"CU",
#"537", #"CY", #"420", #"CZ", #"45", #"DK", #"253", #"DJ",
#"1", #"DM", #"1", #"DO", #"593", #"EC", #"20", #"EG",
#"503", #"SV", #"240", #"GQ", #"291", #"ER", #"372", #"EE",
#"251", #"ET", #"298", #"FO", #"679", #"FJ", #"358", #"FI",
#"33", #"FR", #"594", #"GF", #"689", #"PF", #"241", #"GA",
#"220", #"GM", #"995", #"GE", #"49", #"DE", #"233", #"GH",
#"350", #"GI", #"30", #"GR", #"299", #"GL", #"1", #"GD",
#"590", #"GP", #"1", #"GU", #"502", #"GT", #"224", #"GN",
#"245", #"GW", #"595", #"GY", #"509", #"HT", #"504", #"HN",
#"36", #"HU", #"354", #"IS", #"91", #"IN", #"62", #"ID",
#"964", #"IQ", #"353", #"IE", #"972", #"IL", #"39", #"IT",
#"1", #"JM", #"81", #"JP", #"962", #"JO", #"77", #"KZ",
#"254", #"KE", #"686", #"KI", #"965", #"KW", #"996", #"KG",
#"371", #"LV", #"961", #"LB", #"266", #"LS", #"231", #"LR",
#"423", #"LI", #"370", #"LT", #"352", #"LU", #"261", #"MG",
#"265", #"MW", #"60", #"MY", #"960", #"MV", #"223", #"ML",
#"356", #"MT", #"692", #"MH", #"596", #"MQ", #"222", #"MR",
#"230", #"MU", #"262", #"YT", #"52", #"MX", #"377", #"MC",
#"976", #"MN", #"382", #"ME", #"1", #"MS", #"212", #"MA",
#"95", #"MM", #"264", #"NA", #"674", #"NR", #"977", #"NP",
#"31", #"NL", #"599", #"AN", #"687", #"NC", #"64", #"NZ",
#"505", #"NI", #"227", #"NE", #"234", #"NG", #"683", #"NU",
#"672", #"NF", #"1", #"MP", #"47", #"NO", #"968", #"OM",
#"92", #"PK", #"680", #"PW", #"507", #"PA", #"675", #"PG",
#"595", #"PY", #"51", #"PE", #"63", #"PH", #"48", #"PL",
#"351", #"PT", #"1", #"PR", #"974", #"QA", #"40", #"RO",
#"250", #"RW", #"685", #"WS", #"378", #"SM", #"966", #"SA",
#"221", #"SN", #"381", #"RS", #"248", #"SC", #"232", #"SL",
#"65", #"SG", #"421", #"SK", #"386", #"SI", #"677", #"SB",
#"27", #"ZA", #"500", #"GS", #"34", #"ES", #"94", #"LK",
#"249", #"SD", #"597", #"SR", #"268", #"SZ", #"46", #"SE",
#"41", #"CH", #"992", #"TJ", #"66", #"TH", #"228", #"TG",
#"690", #"TK", #"676", #"TO", #"1", #"TT", #"216", #"TN",
#"90", #"TR", #"993", #"TM", #"1", #"TC", #"688", #"TV",
#"256", #"UG", #"380", #"UA", #"971", #"AE", #"44", #"GB",
#"1", #"US", #"598", #"UY", #"998", #"UZ", #"678", #"VU",
#"681", #"WF", #"967", #"YE", #"260", #"ZM", #"263", #"ZW",
#"591", #"BO", #"673", #"BN", #"61", #"CC", #"243", #"CD",
#"225", #"CI", #"500", #"FK", #"44", #"GG", #"379", #"VA",
#"852", #"HK", #"98", #"IR", #"44", #"IM", #"44", #"JE",
#"850", #"KP", #"82", #"KR", #"856", #"LA", #"218", #"LY",
#"853", #"MO", #"389", #"MK", #"691", #"FM", #"373", #"MD",
#"258", #"MZ", #"970", #"PS", #"872", #"PN", #"262", #"RE",
#"7", #"RU", #"590", #"BL", #"290", #"SH", #"1", #"KN",
#"1", #"LC", #"590", #"MF", #"508", #"PM", #"1", #"VC",
#"239", #"ST", #"252", #"SO", #"47", #"SJ", #"963", #"SY",
#"886", #"TW", #"255", #"TZ", #"670", #"TL", #"58", #"VE",
#"84", #"VN", #"1", #"VG", #"1", #"VI", nil];
return dictCodes;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
T*t = [[T alloc] init];
NSLog(#"%#", [t convertNumberToInternational:#"05135897"]);
NSLog(#"%#", [t convertNumberToInternational:#"00995135897"]);
}
}
Probably you could use NSFormatter class.
Validate the total length of the telephone number. (Which will be entered and read as NSString)
There may be few things you may require to do like, skip the first part i.e. 0.
I can't find an answer to account for error code 21007. I understand that apple tests in-app purchases using sandbox environment, but how can I account for this in the following code.
#import "VerificationController.h"
#import "NSData+Base64.h"
static VerificationController *singleton;
#implementation VerificationController {
NSMutableDictionary * _completionHandlers;
NSString *SendURL;
}
+ (VerificationController *)sharedInstance
{
if (singleton == nil)
{
singleton = [[VerificationController alloc] init];
}
return singleton;
}
- (id)init
{
self = [super init];
if (self != nil)
{
transactionsReceiptStorageDictionary = [[NSMutableDictionary alloc] init];
_completionHandlers = [[NSMutableDictionary alloc] init];
}
return self;
}
- (NSDictionary *)dictionaryFromPlistData:(NSData *)data
{
NSError *error;
NSDictionary *dictionaryParsed = [NSPropertyListSerialization propertyListWithData:data
options:NSPropertyListImmutable
format:nil
error:&error];
if (!dictionaryParsed)
{
if (error)
{
NSLog(#"Error parsing plist");
}
return nil;
}
return dictionaryParsed;
}
- (NSDictionary *)dictionaryFromJSONData:(NSData *)data
{
NSError *error;
NSDictionary *dictionaryParsed = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
if (!dictionaryParsed)
{
if (error)
{
NSLog(#"Error parsing dictionary");
}
return nil;
}
return dictionaryParsed;
}
#pragma mark Receipt Verification
// This method should be called once a transaction gets to the SKPaymentTransactionStatePurchased or SKPaymentTransactionStateRestored state
// Call it with the SKPaymentTransaction.transactionReceipt
- (void)verifyPurchase:(SKPaymentTransaction *)transaction completionHandler: (VerifyCompletionHandler)completionHandler
{
BOOL isOk = [self isTransactionAndItsReceiptValid:transaction];
if (!isOk)
{
// There was something wrong with the transaction we got back, so no need to call verifyReceipt.
NSLog(#"Invalid transacion");
completionHandler(FALSE);
return;
}
// The transaction looks ok, so start the verify process.
// Encode the receiptData for the itms receipt verification POST request.
NSString *jsonObjectString = [self encodeBase64:(uint8_t *)transaction.transactionReceipt.bytes
length:transaction.transactionReceipt.length];
// Create the POST request payload.
NSString *payload = [NSString stringWithFormat:#"{\"receipt-data\" : \"%#\", \"password\" : \"%#\"}",
jsonObjectString, ITC_CONTENT_PROVIDER_SHARED_SECRET];
NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
#warning Check for the correct itms verify receipt URL
// Use ITMS_SANDBOX_VERIFY_RECEIPT_URL while testing against the sandbox.
NSString *serverURL = SendURL;
// Create the POST request to the server.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serverURL]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:payloadData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
_completionHandlers[[NSValue valueWithNonretainedObject:conn]] = completionHandler;
[conn start];
// The transation receipt has not been validated yet. That is done from the NSURLConnection callback.
}
// Check the validity of the receipt. If it checks out then also ensure the transaction is something
// we haven't seen before and then decode and save the purchaseInfo from the receipt for later receipt validation.
- (BOOL)isTransactionAndItsReceiptValid:(SKPaymentTransaction *)transaction
{
if (!(transaction && transaction.transactionReceipt && [transaction.transactionReceipt length] > 0))
{
// Transaction is not valid.
return NO;
}
// Pull the purchase-info out of the transaction receipt, decode it, and save it for later so
// it can be cross checked with the verifyReceipt.
NSDictionary *receiptDict = [self dictionaryFromPlistData:transaction.transactionReceipt];
NSString *transactionPurchaseInfo = [receiptDict objectForKey:#"purchase-info"];
NSString *decodedPurchaseInfo = [self decodeBase64:transactionPurchaseInfo length:nil];
NSDictionary *purchaseInfoDict = [self dictionaryFromPlistData:[decodedPurchaseInfo dataUsingEncoding:NSUTF8StringEncoding]];
NSString *transactionId = [purchaseInfoDict objectForKey:#"transaction-id"];
NSString *purchaseDateString = [purchaseInfoDict objectForKey:#"purchase-date"];
NSString *signature = [receiptDict objectForKey:#"signature"];
// Convert the string into a date
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss z"];
NSDate *purchaseDate = [dateFormat dateFromString:[purchaseDateString stringByReplacingOccurrencesOfString:#"Etc/" withString:#""]];
if (![self isTransactionIdUnique:transactionId])
{
// We've seen this transaction before.
// Had [transactionsReceiptStorageDictionary objectForKey:transactionId]
// Got purchaseInfoDict
return NO;
}
// Check the authenticity of the receipt response/signature etc.
BOOL result = checkReceiptSecurity(transactionPurchaseInfo, signature,
(__bridge CFDateRef)(purchaseDate));
if (!result)
{
return NO;
}
// Ensure the transaction itself is legit
if (![self doTransactionDetailsMatchPurchaseInfo:transaction withPurchaseInfo:purchaseInfoDict])
{
return NO;
}
// Make a note of the fact that we've seen the transaction id already
[self saveTransactionId:transactionId];
// Save the transaction receipt's purchaseInfo in the transactionsReceiptStorageDictionary.
[transactionsReceiptStorageDictionary setObject:purchaseInfoDict forKey:transactionId];
return YES;
}
// Make sure the transaction details actually match the purchase info
- (BOOL)doTransactionDetailsMatchPurchaseInfo:(SKPaymentTransaction *)transaction withPurchaseInfo:(NSDictionary *)purchaseInfoDict
{
if (!transaction || !purchaseInfoDict)
{
return NO;
}
int failCount = 0;
if (![transaction.payment.productIdentifier isEqualToString:[purchaseInfoDict objectForKey:#"product-id"]])
{
failCount++;
}
if (transaction.payment.quantity != [[purchaseInfoDict objectForKey:#"quantity"] intValue])
{
failCount++;
}
if (![transaction.transactionIdentifier isEqualToString:[purchaseInfoDict objectForKey:#"transaction-id"]])
{
failCount++;
}
// Optionally check the bid and bvrs match this app's current bundle ID and bundle version.
// Optionally check the requestData.
// Optionally check the dates.
if (failCount != 0)
{
return NO;
}
// The transaction and its signed content seem ok.
return YES;
}
- (BOOL)isTransactionIdUnique:(NSString *)transactionId
{
NSString *transactionDictionary = KNOWN_TRANSACTIONS_KEY;
// Save the transactionId to the standardUserDefaults so we can check against that later
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize];
if (![defaults objectForKey:transactionDictionary])
{
[defaults setObject:[[NSMutableDictionary alloc] init] forKey:transactionDictionary];
[defaults synchronize];
}
if (![[defaults objectForKey:transactionDictionary] objectForKey:transactionId])
{
return YES;
}
// The transaction already exists in the defaults.
return NO;
}
- (void)saveTransactionId:(NSString *)transactionId
{
// Save the transactionId to the standardUserDefaults so we can check against that later
// If dictionary exists already then retrieve it and add new transactionID
// Regardless save transactionID to dictionary which gets saved to NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *transactionDictionary = KNOWN_TRANSACTIONS_KEY;
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithDictionary:
[defaults objectForKey:transactionDictionary]];
if (!dictionary)
{
dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:1], transactionId, nil];
} else {
[dictionary setObject:[NSNumber numberWithInt:1] forKey:transactionId];
}
[defaults setObject:dictionary forKey:transactionDictionary];
[defaults synchronize];
}
- (BOOL)doesTransactionInfoMatchReceipt:(NSString*) receiptString
{
// Convert the responseString into a dictionary and pull out the receipt data.
NSDictionary *verifiedReceiptDictionary = [self dictionaryFromJSONData:[receiptString dataUsingEncoding:NSUTF8StringEncoding]];
// Check the status of the verifyReceipt call
id status = [verifiedReceiptDictionary objectForKey:#"status"];
if (!status)
{
return NO;
}
int verifyReceiptStatus = [status integerValue];
// 21006 = This receipt is valid but the subscription has expired.
NSLog(#"Status Code: %#", status);
if (0 != verifyReceiptStatus && 21006 != verifyReceiptStatus)
{
return NO;
}
// The receipt is valid, so checked the receipt specifics now.
NSDictionary *verifiedReceiptReceiptDictionary = [verifiedReceiptDictionary objectForKey:#"receipt"];
NSString *verifiedReceiptUniqueIdentifier = [verifiedReceiptReceiptDictionary objectForKey:#"unique_identifier"];
NSString *transactionIdFromVerifiedReceipt = [verifiedReceiptReceiptDictionary objectForKey:#"transaction_id"];
// Get the transaction's receipt data from the transactionsReceiptStorageDictionary
NSDictionary *purchaseInfoFromTransaction = [transactionsReceiptStorageDictionary objectForKey:transactionIdFromVerifiedReceipt];
if (!purchaseInfoFromTransaction)
{
// We didn't find a receipt for this transaction.
return NO;
}
// NOTE: Instead of counting errors you could just return early.
int failCount = 0;
// Verify all the receipt specifics to ensure everything matches up as expected
if (![[verifiedReceiptReceiptDictionary objectForKey:#"bid"]
isEqualToString:[purchaseInfoFromTransaction objectForKey:#"bid"]])
{
failCount++;
}
if (![[verifiedReceiptReceiptDictionary objectForKey:#"product_id"]
isEqualToString:[purchaseInfoFromTransaction objectForKey:#"product-id"]])
{
failCount++;
}
if (![[verifiedReceiptReceiptDictionary objectForKey:#"quantity"]
isEqualToString:[purchaseInfoFromTransaction objectForKey:#"quantity"]])
{
failCount++;
}
if (![[verifiedReceiptReceiptDictionary objectForKey:#"item_id"]
isEqualToString:[purchaseInfoFromTransaction objectForKey:#"item-id"]])
{
failCount++;
}
if ([[UIDevice currentDevice] respondsToSelector:NSSelectorFromString(#"identifierForVendor")]) // iOS 6?
{
#if IS_IOS6_AWARE
// iOS 6 (or later)
NSString *localIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
NSString *purchaseInfoUniqueVendorId = [purchaseInfoFromTransaction objectForKey:#"unique-vendor-identifier"];
NSString *verifiedReceiptVendorIdentifier = [verifiedReceiptReceiptDictionary objectForKey:#"unique_vendor_identifier"];
if(verifiedReceiptVendorIdentifier)
{
if (![purchaseInfoUniqueVendorId isEqualToString:verifiedReceiptVendorIdentifier]
|| ![purchaseInfoUniqueVendorId isEqualToString:localIdentifier])
{
// Comment this line out to test in the Simulator.
failCount++;
}
}
#endif
} else {
// Pre iOS 6
// NSString *localIdentifier = [UIDevice currentDevice].uniqueIdentifier;
NSString *localIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
NSString *purchaseInfoUniqueId = [purchaseInfoFromTransaction objectForKey:#"unique-identifier"];
if (![purchaseInfoUniqueId isEqualToString:verifiedReceiptUniqueIdentifier]
|| ![purchaseInfoUniqueId isEqualToString:localIdentifier])
{
// Comment this line out to test in the Simulator.
failCount++;
}
}
// Do addition time checks for the transaction and receipt.
if(failCount != 0)
{
return NO;
}
return YES;
}
#pragma mark NSURLConnectionDelegate (for the verifyReceipt connection)
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Connection failure: %#", error);
VerifyCompletionHandler completionHandler = _completionHandlers[[NSValue valueWithNonretainedObject:connection]];
[_completionHandlers removeObjectForKey:[NSValue valueWithNonretainedObject:connection]];
completionHandler(FALSE);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// So we got some receipt data. Now does it all check out?
BOOL isOk = [self doesTransactionInfoMatchReceipt:responseString];
VerifyCompletionHandler completionHandler = _completionHandlers[[NSValue valueWithNonretainedObject:connection]];
[_completionHandlers removeObjectForKey:[NSValue valueWithNonretainedObject:connection]];
if (isOk)
{
//Validation suceeded. Unlock content here.
NSLog(#"Validation successful");
completionHandler(TRUE);
} else {
NSLog(#"Validation failed");
completionHandler(FALSE);
}
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge
{
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust])
{
SecTrustRef trust = [[challenge protectionSpace] serverTrust];
NSError *error = nil;
BOOL didUseCredential = NO;
BOOL isTrusted = [self validateTrust:trust error:&error];
if (isTrusted)
{
NSURLCredential *trust_credential = [NSURLCredential credentialForTrust:trust];
if (trust_credential)
{
[[challenge sender] useCredential:trust_credential forAuthenticationChallenge:challenge];
didUseCredential = YES;
}
}
if (!didUseCredential)
{
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
} else {
[[challenge sender] performDefaultHandlingForAuthenticationChallenge:challenge];
}
}
// NOTE: These are needed for 4.x (as willSendRequestForAuthenticationChallenge: is not supported)
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace: (NSURLProtectionSpace *)protectionSpace
{
return [[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust])
{
SecTrustRef trust = [[challenge protectionSpace] serverTrust];
NSError *error = nil;
BOOL didUseCredential = NO;
BOOL isTrusted = [self validateTrust:trust error:&error];
if (isTrusted)
{
NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];
if (credential)
{
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
didUseCredential = YES;
}
}
if (! didUseCredential) {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
} else {
[[challenge sender] performDefaultHandlingForAuthenticationChallenge:challenge];
}
}
#pragma mark
#pragma mark NSURLConnection - Trust validation
- (BOOL)validateTrust:(SecTrustRef)trust error:(NSError **)error
{
// Include some Security framework SPIs
extern CFStringRef kSecTrustInfoExtendedValidationKey;
extern CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust);
BOOL trusted = NO;
SecTrustResultType trust_result;
if ((noErr == SecTrustEvaluate(trust, &trust_result)) && (trust_result == kSecTrustResultUnspecified))
{
NSDictionary *trust_info = (__bridge_transfer NSDictionary *)SecTrustCopyInfo(trust);
id hasEV = [trust_info objectForKey:(__bridge NSString *)kSecTrustInfoExtendedValidationKey];
trusted = [hasEV isKindOfClass:[NSValue class]] && [hasEV boolValue];
}
if (trust)
{
if (!trusted && error)
{
*error = [NSError errorWithDomain:#"kSecTrustError" code:(NSInteger)trust_result userInfo:nil];
}
return trusted;
}
return NO;
}
#pragma mark
#pragma mark Check Receipt signature
#include <CommonCrypto/CommonDigest.h>
#include <Security/Security.h>
#include <AssertMacros.h>
unsigned int iTS_intermediate_der_len = 1039;
unsigned char iTS_intermediate_der[] = {
0x30, 0x82, 0x04, 0x0b, 0x30, 0x82, 0x02, 0xf3, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x01, 0x1a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x62, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70,
0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x26, 0x30, 0x24, 0x06,
0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, 0x41, 0x70,
0x70, 0x6c, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x35, 0x31, 0x39, 0x31, 0x38, 0x33,
0x31, 0x33, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x35, 0x31, 0x38,
0x31, 0x38, 0x33, 0x31, 0x33, 0x30, 0x5a, 0x30, 0x7f, 0x31, 0x0b, 0x30,
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70,
0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x26, 0x30, 0x24, 0x06,
0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2a, 0x41, 0x70,
0x70, 0x6c, 0x65, 0x20, 0x69, 0x54, 0x75, 0x6e, 0x65, 0x73, 0x20, 0x53,
0x74, 0x6f, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
0x00, 0xa4, 0xbc, 0xaf, 0x32, 0x94, 0x43, 0x3e, 0x0b, 0xbc, 0x37, 0x87,
0xcd, 0x63, 0x89, 0xf2, 0xcc, 0xd9, 0xbe, 0x20, 0x4d, 0x5a, 0xb4, 0xfe,
0x87, 0x67, 0xd2, 0x9a, 0xde, 0x1a, 0x54, 0x9d, 0xa2, 0xf3, 0xdf, 0x87,
0xe4, 0x4c, 0xcb, 0x93, 0x11, 0x78, 0xa0, 0x30, 0x8f, 0x34, 0x41, 0xc1,
0xd3, 0xbe, 0x66, 0x6d, 0x47, 0x6c, 0x98, 0xb8, 0xec, 0x7a, 0xd5, 0xc9,
0xdd, 0xa5, 0xe4, 0xea, 0xc6, 0x70, 0xf4, 0x35, 0xd0, 0x91, 0xf7, 0xb3,
0xd8, 0x0a, 0x11, 0x99, 0xab, 0x3a, 0x62, 0x3a, 0xbd, 0x7b, 0xf4, 0x56,
0x4f, 0xdb, 0x9f, 0x24, 0x93, 0x51, 0x50, 0x7c, 0x20, 0xd5, 0x66, 0x4d,
0x66, 0xf3, 0x18, 0xa4, 0x13, 0x96, 0x22, 0x16, 0xfd, 0x31, 0xa7, 0xf4,
0x39, 0x66, 0x9b, 0xfb, 0x62, 0x69, 0x5c, 0x4b, 0x9f, 0x94, 0xa8, 0x4b,
0xe8, 0xec, 0x5b, 0x64, 0x5a, 0x18, 0x79, 0x8a, 0x16, 0x75, 0x63, 0x42,
0xa4, 0x49, 0xd9, 0x8c, 0x33, 0xde, 0xad, 0x7b, 0xd6, 0x39, 0x04, 0xf4,
0xe2, 0x9d, 0x0a, 0x69, 0x8c, 0xeb, 0x4b, 0x12, 0x28, 0x4b, 0x34, 0x48,
0x07, 0x9b, 0x0e, 0x59, 0xf9, 0x1f, 0x62, 0xb0, 0x03, 0x9f, 0x36, 0xb8,
0x4e, 0xa3, 0xd3, 0x75, 0x59, 0xd4, 0xf3, 0x3a, 0x05, 0xca, 0xc5, 0x33,
0x3b, 0xf8, 0xc0, 0x06, 0x09, 0x08, 0x93, 0xdb, 0xe7, 0x4d, 0xbf, 0x11,
0xf3, 0x52, 0x2c, 0xa5, 0x16, 0x35, 0x15, 0xf3, 0x41, 0x02, 0xcd, 0x02,
0xd1, 0xfc, 0xf5, 0xf8, 0xc5, 0x84, 0xbd, 0x63, 0x6a, 0x86, 0xd6, 0xb6,
0x99, 0xf6, 0x86, 0xae, 0x5f, 0xfd, 0x03, 0xd4, 0x28, 0x8a, 0x5a, 0x5d,
0xaf, 0xbc, 0x65, 0x74, 0xd1, 0xf7, 0x1a, 0xc3, 0x92, 0x08, 0xf4, 0x1c,
0xad, 0x69, 0xe8, 0x02, 0x4c, 0x0e, 0x95, 0x15, 0x07, 0xbc, 0xbe, 0x6a,
0x6f, 0xc1, 0xb3, 0xad, 0xa1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
0xae, 0x30, 0x81, 0xab, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03,
0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
0x36, 0x1d, 0xe8, 0xe2, 0x9d, 0x82, 0xd2, 0x01, 0x18, 0xb5, 0x32, 0x6b,
0x0e, 0xd7, 0x43, 0x0b, 0x91, 0x58, 0x43, 0x3a, 0x30, 0x1f, 0x06, 0x03,
0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x2b, 0xd0, 0x69,
0x47, 0x94, 0x76, 0x09, 0xfe, 0xf4, 0x6b, 0x8d, 0x2e, 0x40, 0xa6, 0xf7,
0x47, 0x4d, 0x7f, 0x08, 0x5e, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f,
0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25,
0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61,
0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x70,
0x6c, 0x65, 0x63, 0x61, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72,
0x6c, 0x30, 0x10, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63, 0x64,
0x06, 0x02, 0x02, 0x04, 0x02, 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
0x01, 0x01, 0x00, 0x75, 0xa6, 0x90, 0xe6, 0x9a, 0xa7, 0xdb, 0x65, 0x70,
0xa6, 0x09, 0x93, 0x6f, 0x08, 0xdf, 0x2c, 0xdb, 0xe9, 0x28, 0x8d, 0x40,
0x1b, 0x57, 0x5e, 0xa0, 0xea, 0xf4, 0xec, 0x13, 0x65, 0x1b, 0x71, 0x4a,
0x4d, 0xdc, 0x80, 0x48, 0x4f, 0xf2, 0xe5, 0xa9, 0xfb, 0x85, 0x6c, 0xb7,
0x1e, 0x9d, 0xdb, 0xf4, 0x18, 0x48, 0x10, 0x79, 0x17, 0xea, 0xc3, 0x3d,
0x87, 0xd8, 0xb4, 0x79, 0x6d, 0x14, 0x50, 0xad, 0xd2, 0xbf, 0x3d, 0x4e,
0xfc, 0x0d, 0xe2, 0xc5, 0x03, 0x94, 0x75, 0x80, 0x73, 0x4d, 0xa5, 0xa1,
0x91, 0xfe, 0x1c, 0xde, 0x15, 0x17, 0xac, 0x89, 0x71, 0x2a, 0x6f, 0x0f,
0x67, 0x0a, 0xd3, 0x9c, 0x30, 0xa1, 0x68, 0xfb, 0xcf, 0x70, 0x17, 0xca,
0xd9, 0x40, 0xfc, 0xf8, 0x1b, 0xbf, 0xce, 0xb0, 0xc4, 0xae, 0xf4, 0x4a,
0x2d, 0xa9, 0x99, 0x87, 0x06, 0x42, 0x09, 0x86, 0x22, 0x6a, 0x84, 0x40,
0x39, 0xf4, 0xbb, 0xac, 0x56, 0x18, 0xf7, 0x9a, 0x1c, 0x01, 0x81, 0x5c,
0x8c, 0x6e, 0x41, 0xf2, 0x5d, 0x19, 0x2c, 0x17, 0x1c, 0x49, 0x46, 0xd9,
0x1c, 0x7e, 0x93, 0x12, 0x13, 0xc8, 0x67, 0x99, 0xc2, 0xea, 0x83, 0xe3,
0xa2, 0x8c, 0x0e, 0xb8, 0x3b, 0x2a, 0xdf, 0x1c, 0xbf, 0x4b, 0x8b, 0x6f,
0x1a, 0xb8, 0xee, 0x97, 0x67, 0x4a, 0xd8, 0xab, 0xaf, 0x8b, 0xa4, 0xda,
0x5c, 0x87, 0x1e, 0x20, 0xb8, 0xc5, 0xf3, 0xb1, 0xc4, 0x98, 0xa2, 0x37,
0xf8, 0x9e, 0xc6, 0x9a, 0x6b, 0xa5, 0xad, 0xf6, 0x78, 0x96, 0x0e, 0x82,
0x8f, 0x04, 0x46, 0x1c, 0xb2, 0xa5, 0xfd, 0x9a, 0x30, 0x51, 0x28, 0xfd,
0x52, 0x04, 0x15, 0x03, 0xd5, 0x3c, 0xad, 0xfe, 0xf6, 0x78, 0xe0, 0xea,
0x35, 0xef, 0x65, 0xb5, 0x21, 0x76, 0xdb, 0xa4, 0xef, 0xcb, 0x72, 0xef,
0x54, 0x6b, 0x01, 0x0d, 0xc7, 0xdd, 0x1a
};
BOOL checkReceiptSecurity(NSString *purchase_info_string, NSString *signature_string, CFDateRef purchaseDate)
{
BOOL valid = NO;
SecCertificateRef leaf = NULL, intermediate = NULL;
SecTrustRef trust = NULL;
SecPolicyRef policy = SecPolicyCreateBasicX509();
NSData *certificate_data;
NSArray *anchors;
/*
Parse inputs:
purchase_info_string and signature_string are base64 encoded JSON blobs that need to
be decoded.
*/
require([purchase_info_string canBeConvertedToEncoding:NSASCIIStringEncoding] &&
[signature_string canBeConvertedToEncoding:NSASCIIStringEncoding], outLabel);
size_t purchase_info_length;
uint8_t *purchase_info_bytes = base64_decode([purchase_info_string cStringUsingEncoding:NSASCIIStringEncoding],
&purchase_info_length);
size_t signature_length;
uint8_t *signature_bytes = base64_decode([signature_string cStringUsingEncoding:NSASCIIStringEncoding],
&signature_length);
require(purchase_info_bytes && signature_bytes, outLabel);
/*
Binary format looks as follows:
RECEIPTVERSION | SIGNATURE | CERTIFICATE SIZE | CERTIFICATE
1 byte 128 4 bytes
big endian
Extract version, signature and certificate(s).
Check receipt version == 2.
Sanity check that signature is 128 bytes.
Sanity check certificate size <= remaining payload data.
*/
It's been a very long time, but i hope i can solve your problem.
Well, the 21007 code means you're trying to validate a sandbox receipt though the production validation url.
This is how i did with my code: Calling the method below.
[self validarTransacao:transacao naStoreURL:#"https://buy.itunes.apple.com/verifyReceipt"];
1 - tries to validate the receipt through the production validation url, and then, if it returns 21007, i try the sandbox url instead.
-(void)validarTransacao:(SKPaymentTransaction *)transacao naStoreURL:(NSString *)url
{
receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
if (!receipt)
{
receipt = transacao.transactionReceipt;
}
NSError *erro;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[NSJSONSerialization dataWithJSONObject:#{#"receipt-data": [receipt base64EncodedStringWithOptions:0], #"password" : #"1234567890123456789"} options:0 error:&erro]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if (!connectionError)
{
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSLog(#"%i", [[jsonResponse objectForKey:#"status"] intValue]);
if ([[jsonResponse objectForKey:#"status"] intValue] == 0)
{
// Authorized
}
else
{
// Receipt error
switch ([[jsonResponse objectForKey:#"status"] intValue])
{
case 21000:
// Not possible to read the receipt
break;
case 21002:
// Receipt not sent
break;
case 21003:
// Not authenticated
break;
case 21004:
// Shared secret not found
break;
case 21005:
// Server not available
[SVProgressHUD showErrorWithStatus:#"Não foi possível conectar com a AppStore. Faremos uma nova tentativa em breve"];
break;
case 21006:
// Valid receipt, subsctiption expired
break;
case 21007:
// Test receipt try on sandbox
[self validarTransacao:transacao naStoreURL:#"https://sandbox.itunes.apple.com/verifyReceipt"];
break;
case 21008:
// Production receipt try on buy
[self validarTransacao:transacao naStoreURL:#"https://buy.itunes.apple.com/verifyReceipt"];
break;
}
}
}
else
{
[SVProgressHUD showErrorWithStatus:#"Não foi possível conectar com a AppStore. Faremos uma nova tentativa em breve"];
}
}];
}
That`s it!
I have to pass data between table view controller and detail view controller, and I'm using Parse to load the data from backend, I have do this with local data, this is the source code:
Table view controller:
#import "RecipeBookViewController.h"
#import "RecipeDetailViewController.h"
#import "Recipe.h"
#interface RecipeBookViewController ()
#end
#implementation RecipeBookViewController {
NSArray *recipes;
}
#synthesize tableView = _tableView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Initialize table data
// recipes = [NSArray arrayWithObjects:#"Egg Benedict", #"Mushroom Risotto", #"Full Breakfast", #"Hamburger", #"Ham and Egg Sandwich", #"Creme Brelee", #"White Chocolate Donut", #"Starbucks Coffee", #"Vegetable Curry", #"Instant Noodle with Egg", #"Noodle with BBQ Pork", #"Japanese Noodle with Pork", #"Green Tea", #"Thai Shrimp Cake", #"Angry Birds Cake", #"Ham and Cheese Panini", nil];
Recipe *recipe1 = [Recipe new];
recipe1.name = #"Egg Benedict";
recipe1.prepTime = #"30 min";
recipe1.imageFile = #"egg_benedict.jpg";
recipe1.ingredients = [NSArray arrayWithObjects:#"2 fresh English muffins", #"4 eggs", #"4 rashers of back bacon", #"2 egg yolks", #"1 tbsp of lemon juice", #"125 g of butter", #"salt and pepper", nil];
Recipe *recipe2 = [Recipe new];
recipe2.name = #"Mushroom Risotto";
recipe2.prepTime = #"30 min";
recipe2.imageFile = #"mushroom_risotto.jpg";
recipe2.ingredients = [NSArray arrayWithObjects:#"1 tbsp dried porcini mushrooms", #"2 tbsp olive oil", #"1 onion, chopped", #"2 garlic cloves", #"350g/12oz arborio rice", #"1.2 litres/2 pints hot vegetable stock", #"salt and pepper", #"25g/1oz butter", nil];
Recipe *recipe3 = [Recipe new];
recipe3.name = #"Full Breakfast";
recipe3.prepTime = #"20 min";
recipe3.imageFile = #"full_breakfast.jpg";
recipe3.ingredients = [NSArray arrayWithObjects:#"2 sausages", #"100 grams of mushrooms", #"2 rashers of bacon", #"2 eggs", #"150 grams of baked beans", #"Vegetable oil", nil];
Recipe *recipe4 = [Recipe new];
recipe4.name = #"Hamburger";
recipe4.prepTime = #"30 min";
recipe4.imageFile = #"hamburger.jpg";
recipe4.ingredients = [NSArray arrayWithObjects:#"400g of ground beef", #"1/4 onion (minced)", #"1 tbsp butter", #"hamburger bun", #"1 teaspoon dry mustard", #"Salt and pepper", nil];
Recipe *recipe5 = [Recipe new];
recipe5.name = #"Ham and Egg Sandwich";
recipe5.prepTime = #"10 min";
recipe5.imageFile = #"ham_and_egg_sandwich.jpg";
recipe5.ingredients = [NSArray arrayWithObjects:#"1 unsliced loaf (1 pound) French bread", #"4 tablespoons butter", #"2 tablespoons mayonnaise", #"8 thin slices deli ham", #"1 large tomato, sliced", #"1 small onion", #"8 eggs", #"8 slices cheddar cheese", nil];
Recipe *recipe6 = [Recipe new];
recipe6.name = #"Creme Brelee";
recipe6.prepTime = #"1 hour";
recipe6.imageFile = #"creme_brelee.jpg";
recipe6.ingredients = [NSArray arrayWithObjects:#"1 quart heavy cream", #"1 vanilla bean, split and scraped", #"1 cup vanilla sugar", #"6 large egg yolks", #"2 quarts hot water", nil];
Recipe *recipe7 = [Recipe new];
recipe7.name = #"White Chocolate Donut";
recipe7.prepTime = #"45 min";
recipe7.imageFile = #"white_chocolate_donut.jpg";
recipe7.ingredients = [NSArray arrayWithObjects:#"3 1/4 cups flour", #"2 teaspoons baking powder", #"1/4 teaspoon salt", #"2 beaten eggs", #"2/3 cup sugar", #"2 ounces melted white chocolate", #"1/2 cup milk", nil];
Recipe *recipe8 = [Recipe new];
recipe8.name = #"White Chocolate Mocha";
recipe8.prepTime = #"5 min";
recipe8.imageFile = #"starbucks_coffee.jpg";
recipe8.ingredients = [NSArray arrayWithObjects:#"2/3 cup whole milk", #"6 tablespoons white chocolate chips", #"coffee", #"whipped cream", nil];
Recipe *recipe9 = [Recipe new];
recipe9.name = #"Vegetable Curry";
recipe9.prepTime = #"30 min";
recipe9.imageFile = #"vegetable_curry.jpg";
recipe9.ingredients = [NSArray arrayWithObjects:#"1 tablespoon olive oil", #"1 onion, chopped", #"2 cloves garlic", #"2 1/2 tablespoons curry powder", #"2 quarts hot water", nil];
Recipe *recipe10 = [Recipe new];
recipe10.name = #"Instant Noodle with Egg";
recipe10.prepTime = #"8 min";
recipe10.imageFile = #"instant_noodle_with_egg.jpg";
recipe10.ingredients = [NSArray arrayWithObjects:#"1 pack of Instant Noodle", #"2 eggs", nil];
Recipe *recipe11 = [Recipe new];
recipe11.name = #"Noodle with BBQ Pork";
recipe11.prepTime = #"20 min";
recipe11.imageFile = #"noodle_with_bbq_pork.jpg";
recipe11.ingredients = [NSArray arrayWithObjects:#"1 pack of Instant Noodle", #"BBQ pork", #"Salt and Pepper", nil];
Recipe *recipe12 = [Recipe new];
recipe12.name = #"Japanese Noodle with Pork";
recipe12.prepTime = #"20 min";
recipe12.imageFile = #"japanese_noodle_with_pork.jpg";
recipe12.ingredients = [NSArray arrayWithObjects:#"1 pack of Japanese Noodle", #"2 green onions", #"2 garlic cloves, minced", #"4 boneless pork loin chops", nil];
Recipe *recipe13 = [Recipe new];
recipe13.name = #"Green Tea";
recipe13.prepTime = #"5 min";
recipe13.imageFile = #"green_tea.jpg";
recipe13.ingredients = [NSArray arrayWithObjects:#"Green tea", nil];
Recipe *recipe14 = [Recipe new];
recipe14.name = #"Thai Shrimp Cake";
recipe14.prepTime = #"1.5 hours";
recipe14.imageFile = #"thai_shrimp_cake.jpg";
recipe14.ingredients = [NSArray arrayWithObjects:#"8 oz (250g) peeled and deveined raw shrimp", #"2 tablespoons red curry paste", #"1 large egg", #"2 teaspoon fish sauce", #"1 tablespoon sugar", #"2 tablespoons coconut milk", #"2 tablespoons roughly chopped Thai basil leaves", nil];
Recipe *recipe15 = [Recipe new];
recipe15.name = #"Angry Birds Cake";
recipe15.prepTime = #"4 hours";
recipe15.imageFile = #"angry_birds_cake.jpg";
recipe15.ingredients = [NSArray arrayWithObjects:#"12 tablespoons (1 1/2 sticks) unsalted butter", #"2 1/2 cups all-purpose flour", #"1 tablespoon baking powder", #"1 teaspoon salt", #"1 3/4 cups sugar", #"2 large eggs, plus 3 large egg yolks", #"1 cup of milk", nil];
Recipe *recipe16 = [Recipe new];
recipe16.name = #"Ham and Cheese Panini";
recipe16.prepTime = #"10 min";
recipe16.imageFile = #"ham_and_cheese_panini.jpg";
recipe16.ingredients = [NSArray arrayWithObjects:#"2 tablespoons unsalted butter", #"4 cups thinly sliced shallots", #"2 teaspoons fresh thyme", #"1/4 cup grainy Dijon mustard", #"8 slices rustic white bread", #"8 slices Gruyere cheese", #"8 ounces sliced cooked ham", nil];
recipes = [NSArray arrayWithObjects:recipe1, recipe2, recipe3, recipe4, recipe5, recipe6, recipe7, recipe8, recipe9, recipe10, recipe11, recipe12, recipe13, recipe14, recipe15, recipe16, nil];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [recipes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"RecipeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
Recipe *recipe = [recipes objectAtIndex:indexPath.row];
cell.textLabel.text = recipe.name;
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.recipe = [recipes objectAtIndex:indexPath.row];
// Hide bottom tab bar in the detail view
// destViewController.hidesBottomBarWhenPushed = YES;
}
}
Detail View Controller:
#interface RecipeDetailViewController ()
#end
#implementation RecipeDetailViewController
#synthesize recipePhoto;
#synthesize prepTimeLabel;
#synthesize ingredientTextView;
#synthesize recipe;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = recipe.name;
self.prepTimeLabel.text = recipe.prepTime;
self.recipePhoto.image = [UIImage imageNamed:recipe.imageFile];
NSMutableString *ingredientText = [NSMutableString string];
for (NSString* ingredient in recipe.ingredients) {
[ingredientText appendFormat:#"%#\n", ingredient];
}
self.ingredientTextView.text = ingredientText;
}
- (void)viewDidUnload
{
[self setRecipePhoto:nil];
[self setPrepTimeLabel:nil];
[self setIngredientTextView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
How can I do this using the Parse.com backend?
Assuming you have a a Recipe class in the Parse backend, you should be able simply replace the code in your initializer that creates the recipes with a Parse query to retrieve them instead. Something like the following (note I haven't exactly checked syntax):
PFQuery *recipeQuery = [PFQuery queryWithClassName:#"Recipe"];
[recipeQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.recipes = <Map parse objects to Recipe objects here>;
}
}];
If you map the returned Parse objects to Recipe objects, you shouldn't need to change any of the rest of your code, apart from dealing with the delay in loading content over the network (you'd probably want to display some kind of loading indicator to the user).
Alternatively, you could look into the PFQueryTableViewController, provided with Parse framework, which will probably do everything you need.