30
Testing Apps with In App Purchases in Simulator
No comments · Posted by David Linsin in Tutorial
If you add a store to your app and use In App Purchases to collect your payments, there are a couple of limitations your have to live with. One of those limitations is not being able to fully test your App in the iPhone Simulator:
Store Kit does not operate in iPhone Simulator. When running your application in iPhone Simulator, Store Kit logs a warning if your application attempts to retrieve the payment queue. Testing the store must be done on actual devices.
Although, there is not way to test Store Kit itself, you can still test the parts of your App that use and build on the information retrieved from Store Kit. You can use a preprocessor conditional inclusion to determine, whether you are running on the simulator and then “mock” the Store Kit calls or don’t execute them at all.
#if TARGET_IPHONE_SIMULATOR // mock product description #else SKProductsRequest *productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIds]; productRequest.delegate = self; [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; [productRequest start]; #endif
Keep in mind: this might not work for your App, however, it did work for our Apps and it’s better than not testing your code at all. The optimal solution would definitely be to connect to the In App Purchase Sandbox environment from the Simulator.
16
Settings Bundle and Default Values
No comments · Posted by David Linsin in Our Apps, Tutorial
We improved our “I think I spider” App quite a bit since Beta 1. Among other stuff we added some nice sound effects. If you want to check it out, let us know and we’ll hook you up!
If you are like me and not a big fan of sounds, you probably want to turn them off. That’s why we provide a Settings Bundle, which lets you flip a switch in the Settings Application of your iOS device, in order to turn off sounds.
While implementing this feature, we ran into some pitfall with Settings Bundle’s default values. You can define default values in the appropriate Root.plist, like this:
<key>Type</key> <string>PSToggleSwitchSpecifier</string> <key>Title</key> <string>Sound</string> <key>Key</key> <string>sound_enabled</string> <key>DefaultValue</key> <true/>
Unfortuntately, the default value is only applied the first time you access the Settings Application. That means your code cannot rely on the default values and rather has to check manually, if the value has been set in the Settings Application. In case of “I think I spider”, that meant no sound until you accessed the Settings Application. After poking around for a couple of minutes, we found a workaround, which we implemented in our AppDelegate’s didFinishLaunchingWithOptions method:
id test = [[NSUserDefaults standardUserDefaults] objectForKey:@"sound_enabled"];
if (test == NULL) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"sound_enabled"];
}
return YES;
This checks if no value was set, which means the returned value is NULL, and in that case sets our default value. Note that we are duplicating the default value definition here. You could also access the Settings Bundle programmatically and read the default value from there.
This gives us an easy workaround, so that you can enjoy the awesome sound effects in “I think I spider”.
13
On cross-device mobile development – Part 1
No comments · Posted by Florian Krupicka in Tutorial
Once in a while a demand for fast development of a mobile application for several platforms at once comes up. Your team of developers might be small or knowledge about the different Software Development Kits (SDKs) involved is scarce. But hey, perhaps you know how to write HTML & CSS and are also experienced with JavaScript. With the advent of the Apple iPhone and briefly afterwards the Android line of phones, mobile devices started to support a lot of modern HTML & CSS features. The progressing “applification” of the WWW further boosted the development of fast JavaScript engines. And with the recent addition of multitouch, geolocation and fast CSS3 animation support, the mobile browser has become a new deployment target for mobile applications. That’s the theory at least. In this series of articles we will provide an overview on the technologies involved, available frameworks and the approaches taken to bring your application to several mobile platforms at once.
It’s (not) in the browser
Developing applications with HTML, CSS & Javascript is a fundamentally different experience. It already is on the normal desktop with its widescreen browsers. On a mobile device it becomes a game changer. We are accustomed to graphical user interface (GUI) toolkits with their more direct manipulation of data through on-screen elements like buttons. While browsers and HTML provide their own set of UI elements and the ability to wire events like clicks to Javascript callbacks, they lack a lot of the bells and whistles. Especially in the handling of client-side data — the model in model-view-controller (MVC) so to say — and the controller abstraction even modern browsers lack the feature richness of common native SDKs. In the rest of this article we will give a short overview on which web technologies map to which concept in the MVC approach and how you would basically structure an application based on such technologies.
Of models, views & controllers
In “Building iPhone Apps with HTML, CSS and JavaScript” Jonathan Stark describes how to turn websites into single page iPhone applications. Views are implemented straight forward with plain HTML and CSS, throwing in some bits and pieces to make browser standard behavior of HTML elements more native like. To give an example, we will show how to create a graphical navigation bar and switch between different screens. First we need some HTML and CSS snippets to create the layout:
<ul id="navigation"> <li><a class="current" href="#home">Home</a></li> <li><a href="#new">New things</a></li> <li><a href="#favorites">I like those</a></li> <li><a href="#more">More content</a></li> <li><a href="#info">About</a></li> </ul> <div class="view" id="home">...</div> <div class="view" id="new">...</div> <div class="view" id="favorites">...</div> <div class="view" id="more">...</div> <div class="view" id="info">...</div>
The navigational items are then replaced with nice button graphics via CSS and positioned on the page.
/* navigation is a fixed block */
#navigation {
position: fixed; top: 0px; left: 0px;
width: 320px; margin: 0; padding: 0;
}
#navigation li { display: block; position: absolute; }
#navigation li a {
display: block; position: absolute;
height: 48px; width: 80px; top: 0px;
text-indent: -9999px;
}
a[href="#home"] { background: url(home.png); left: 0px; }
a[href="#home"].current { background: url(home-current.png); }
a[href="#new"] { background: url(new.png); left: 80px; }
a[href="#new"].current { background: url(new-current.png); }
a[href="#favorites"] { background: url(favorites.png); left: 160px; }
a[href="#favorites"].current { background: url(favorites-current.png); }
a[href="#more"] { background: url(more.png); left: 240px; }
a[href="#info"] {
background: url(info.png); position: fixed;
width: 48px; height: 48px; bottom: 16px; right: 16px;
}
/* finally position the views themselves */
div.view {
position: absolute; top: 48px; left: 0px;
width: 320px; height: 396px;
}
This can act as a simple framework for an application with multiple views. Now we still need to make our navigation controller to switch between the different views. jQuery to the rescue — a small snippet initializes our view hierarchy and provides switching capabilities:
$(document).ready(function() {
var navitems = $('#navigation li a');
navitems.click(function() {
navitems.removeClass('current');
var ref = $(this).addClass('current').attr('href');
/* hide the other views, show the one navigated to
and trigger a custom event */
$('div.view').hide(); $(ref).show().trigger('becameActive');
});
$('div.view').hide();
$("div.view.current").show().trigger('becameActive');
});
With custom events like becameActive it is easy to create new callbacks that are invoked when state changes occur — in this example when switching the active view through our navigation controller. For brevity we will omit a elaborate example of controller code, but if for example you want code to run when switching to the #new view, you could simply write:
$('#new').bind('becameActive', function(event) {
$(event.target).doSomething();
});
So what is still missing now? We still haven’t provided a data model to operate on. While data provided via web services is not a big deal by the use of JSON-APIs, we would certainly want to have a local data storage too. For quite some time already, web engines provide a local SQLite-based storage system. On application initialization we can simply setup some tables to hold our data and send statements from anywhere in the application later on:
// open a database, providing it's name, version,
// maximum size and display name
var database = openDatabase("Example", "1.0",
1048576, "Example Database");
database.transaction(function(transaction) {
transaction.executeSQL(
"CREATE TABLE IF NOT EXISTS data" +
"(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"... more declarations ...);");
});
// other statements are issued the same way
database.transaction(function(transaction) {
transaction.executeSQL("SELECT * FROM data;",
function(transaction, result) {
// do something with 'result'
});
});
Putting it all together
A question remains: when this is the basic skeleton of an application, how do i put this on an actual device?
While this could be simply served by a web server to a mobile device, the main reason for developing applications instead of websites is the ability to expose them through an application store (e.g. Apples AppStore or the Android Market). We won’t go into much detail here now — this is something to be discussed in the following blog posts in this series — a simple answer is provided by a small framework named PhoneGap. PhoneGap provides the developer with a cross-platform deployment environment, which makes use of the web engines on the different mobile devices. It basically is a fullscreen web browser view, without any UI elements and other decorations but with added support for accessing hardware features of the actual device. Next to the already mentioned features, which are part of the modern web engines, it gives access to features like cameras, accelerometer or access to the native phonebook of your mobile phone. You simply drop all your HTML, CSS & JavaScript into a PhoneGap application package which is built for your particular device and are ready to deploy through any application store or similar channel you like.What’s next?
So developing mobile applications with HTML, CSS & JavaScript is actually easy, isn’t it? Well, with the basic ideas outlined above it is — until it isn’t anymore. In the parts of this series which are still to come, we will answer some questions, that might be crucial to your development cycle:
- What problems might arise with JavaScript as a development language? Is there enough tool support for ease of development?
- What do i have to program from scratch and which frameworks are available, that erase my need of boilerplate code?
- What about the performance, for example when sophisticated animations are desired?
- Is my application really cross-platform, when using these technologies, and does it behave exactly the same on every device?
Stay tuned for more.
android · css · html · iphone · javascript
Our little pet project “I think I spider” is almost ready to be thrown out into the wild!
That means we are running a closed beta for iOS devices for the next couple of weeks. In case you haven’t upgraded your device to Apple’s latest operating system yet, this is the time to do it, because we are targeting iOS 4 only. Unfortunately, we are not ready to support iPad devices yet, but it’s on our radar and planned for a future version.
What about Android? We are working hard on our Android version and it should be ready in the next couple of days! It’ll support a fair number of screen resolutions and various devices.
If you’d like to join our beta, just drop us an email or leave a comment and we’ll hook you up!
27
Sending Apple Push Notifications with notnoop’s java-apns library
No comments · Posted by Tobias Knell in Company
If you need to send apple push notifications to your users, like we do in a secret project mentioned earlier this week, notnoop’s java-apns library is a good choice, because its really simple to use and saves you a lot of work.
(I presume that you already know how to get the Tokens of your users and already have a certificate for the push notifications, I only show you how easy the server part can be with this library. If you don’t know, read this first: Apple Push Service)
First you have to download the library (or add it in your maven dependencies):
java-apns
The programming part isn’t that much so here’s how you do it:
public void pushMessage() {
ApnsService service = null;
try {
// get the certificate
InputStream certStream = this.getClass().getClassLoader().getResourceAsStream("your_certificate.p12");
service = APNS.newService().withCert(certStream, "your_cert_password").withSandboxDestination().build();
// or
// service = APNS.newService().withCert(certStream,
// "your_cert_password").withProductionDestination().build();
service.start();
// You have to delete the devices from you list that no longer
//have the app installed, see method below
deleteInactiveDevices(service);
// read your user list
List userList = userDao.readUsers();
for (User user : userList) {
try {
// we had a daily update here, so we need to know how many
//days the user hasn't started the app
// so that we get the number of updates to display it as the badge.
int days = (int) ((System.currentTimeMillis() - user.getLastUpdate()) / 1000 / 60 / 60 / 24);
PayloadBuilder payloadBuilder = APNS.newPayload();
payloadBuilder = payloadBuilder.badge(days).alertBody("some message you want to send here");
// check if the message is too long (it won't be sent if it is)
//and trim it if it is.
if (payloadBuilder.isTooLong()) {
payloadBuilder = payloadBuilder.shrinkBody();
}
String payload = payloadBuilder.build();
String token = user.getToken();
service.push(token, payload);
} catch (Exception ex) {
// some logging stuff
}
}
} catch (Exception ex) {
// more logging
} finally {
// check if the service was successfull initialized and stop it here, if it was
if (service != null) {
service.stop();
}
}
}
private void deleteInactiveDevices(ApnsService service) {
// get the list of the devices that no longer have your app installed from apple
//ignore the ="" after Date here, it's a bug...
Map inactiveDevices = service.getInactiveDevices();
for (String deviceToken : inactiveDevices.keySet()) {
userDao.deleteByDeviceId(deviceToken);
}
}
Now wasn’t that an easy one this time?
APN · apple · iphone · Push Notification
We are working on a fair number of Apps here at our mobile team and today we are proud to announce one of them: I think I spider!
The “I think I spider” App idea was born, when we discovered the corresponding web site. We had so much fun with it, that we decided to bring all the joy to the major mobile platforms. Thanks to the support of Michael, the master mind behind ithinkispider.com. We were able to use the original silly little quotes, that we all know and love.
The icon you can see here is an idea of our design partner Lars from upstruct. He was kind enough to come up with an outstanding design for the App and we can’t wait for you to see it. You are not only gonna get some crazy quotes, but a really beautiful experience flipping through them.
So we have great content, amazing design and all of that for Android and iPhone devices. We won’t disclose any specifics or feature set yet, since we are working hard on version 1.0, but trust me you will hold it in the head not out.
During development I realized that many device specific features are not available in the emulator. So I decided to find a way to debug software in realtime on the device. First of all I had to upgrade my Device to version PR 1.2. So my SDK and the device libraries had the same version numbers.
I had to install the „maemo pc connectivity“ Package on my N900 and on my host pc.
First I enabled the developer repository on my N900:
catalog name: extras-devel
web address: http://repository.maemo.org/extras-devel
distribution: fremantle
components: free non-free
in a shell on the N900:
sudo gainroot
apt-get install maemo-pc-connectivity gdb
On my Host System I added the repository:
deb http://pc-connectivity.garage.maemo.org/repository intrepid main
and installed host-pc-connectivity by typing:
sudo apt-get update
sudo apt-get instsall host-pc-connectivity
I had a new usb device with an IP address 192.168.2.14.
On my N900 I configured in the system-settings->pc connectivity manager the “default” environment:
connection type: usb
ipadress: 192.168.2.15
gateway: 192.168.2.14
After applying and saving the changes the N900 was ready. I connected it to my pc and opened an ssh shell to the device. I used the username and password I have been asked for while installation on the n900.
In ESBox i had to open the Debug Configurations Dialog and created a new Maemo Remote Application. Most points should be clear. The point Download is interesting: I used
Download Method: ssh
RemoteConnection: 192.168.2.15
Verify the target path. It must be a path that is writeable by the user you have used for the ssh session above. Klick on „Edit“->the link SSH panel and configure the destination folder if necessary.
That was all. The complete documentation of “pc connectivity” can be found here http://pc-connectivity.garage.maemo.org/2nd_edition/index.html. This documentation describes howto use certificates to avoid password fields during the launch process. This is not necessary, simply type the username and password once and check remember.
Have you ever pondered on the NSString class reference and you were overwhelmed by the sheer amount of methods? I certainly have and due to the endless possibilities those methods give you, I just couldn’t figure out how to split an NSString by characters and create a NSArray of those characters.
Blame it on my lack of creativity or on the fact that I’m not a C buff. However, thanks to my creative Googling, I came across this site, which shows you how to do it:
NSMutableArray *characters =
[[NSMutableArray alloc] initWithCapacity:[myString length]];
for (int i=0; i < [myString length]; i++) {
NSString *ichar =
[NSString stringWithFormat:@"%c", [myString characterAtIndex:i]];
[characters addObject:ichar];
}
Although Apple’s documentation is extensive, you sometimes need a little hint or guidance to achieve your goal.
Before flying off to WWDC last month, I watched a whole bunch of sessions from 2009. Among others a session on “Prototyping iPhone User Interfaces” by Bret Victor. If you haven’t watched it and you’ve got access to the WWDC videos – stop right here and watch the video!
In his session, Bret shows how to prototype an interface only by using with screenshots! It’s amazing that a simple screenshot on the device can show you so much more than by just looking at it in a document or print out. It inspired me to use his framework and the whole process for our own development.
Unfortunately, the code for the session isn’t available and neither Bret nor the frameworks evangelist mentioned in the presentation got back to me about the code. After some digging, I found Michael Fey’s blog, who was able to successfully reverse engineer the missing parts, which were not shown in the presentation.
Michael’s UIViewAdditions basically allow easy access to frame properties and give you a neat init method, which adds the passed UIView as a parent:
- (id)initWithParent:(UIView *)parent {
self = [self initWithFrame:CGRectZero];
if (!self)
return nil;
[parent addSubview:self];
return self;
}
+ (id) viewWithParent:(UIView *)parent {
return [[[self alloc] initWithParent:parent] autorelease];
}
There wasn’t much left to do for me. I only coded the class Root, which is the parent of all UIImageView instances used in the prototype. It provides a couple of methods to slide images back and forth:
@synthesize pageIndex = _pageIndex;
- (id) initWithParent:(UIView *)parent { self = [super initWithParent:parent]; if (self == nil) { return nil; } self.userInteractionEnabled = YES; self.size = self.window.size; [[UIImageView viewWithParent:self] setImageWithName:@"dailies"]; self.pageIndex = 0; return self; }
- (void)setPageIndex:(int)index { if (index < 0 || index >= [self.subviews count]) { return; } _pageIndex = index; for (int i = 0; i < [self.subviews count]; i++) { UIImageView *page = [self.subviews objectAtIndex:i]; page.x = (i < _pageIndex) ? -self.width : (i > _pageIndex) ? self.width : 0; } }
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { self.pageIndex++; }
With those two classes and a couple of screenshots, it is fairly easy to create an App that looks and feels almost real. I created a short demo video, which shows how easy it is to get a good feeling if your App is going to work or not:
Now don’t forget those are only screenshots and the App might need to load stuff over the network or do some animation, hence it might not feel exactly the same. However, this process of prototyping an UI is powerful enough to give you an idea, whether the workflow or the UI in general is going to “work” or needs some tweaking.
You can download the source code for the two classes, along with a sample project from github.
apple · design · iphone · objective-c · prototyping
Dealing with self-signed ssl certificates is a real pain, because it’s not that simple to add them in your app and let android accept them.
But fortunately, there’s a workaround that uses an own SSLSocketFactory and an own TrustManager. With this, only your added site is beeing able to be called, so theres no security issue.
First you have to create the SSLFactory:
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.LayeredSocketFactory;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
/**
* This socket factory will create ssl socket that accepts self signed certificate
*
* @author olamy
* @version $Id: EasySSLSocketFactory.java 765355 2009-04-15 20:59:07Z evenisse $
* @since 1.2.3
*/
public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory {
private SSLContext sslcontext = null;
private static SSLContext createEasySSLContext() throws IOException {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] { new EasyX509TrustManager(null) }, null);
return context;
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
private SSLContext getSSLContext() throws IOException {
if (this.sslcontext == null) {
this.sslcontext = createEasySSLContext();
}
return this.sslcontext;
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, java.lang.String, int,
* java.net.InetAddress, int, org.apache.http.params.HttpParams)
*/
public Socket connectSocket(Socket sock, String host, int port, InetAddress localAddress, int localPort,
HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());
if ((localAddress != null) || (localPort > 0)) {
// we need to bind explicitly
if (localPort < 0) {
localPort = 0; // indicates "any"
}
InetSocketAddress isa = new InetSocketAddress(localAddress, localPort);
sslsock.bind(isa);
}
sslsock.connect(remoteAddress, connTimeout);
sslsock.setSoTimeout(soTimeout);
return sslsock;
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#createSocket()
*/
public Socket createSocket() throws IOException {
return getSSLContext().getSocketFactory().createSocket();
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket)
*/
public boolean isSecure(Socket socket) throws IllegalArgumentException {
return true;
}
/**
* @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.String, int,
* boolean)
*/
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
}
// -------------------------------------------------------------------
// javadoc in org.apache.http.conn.scheme.SocketFactory says :
// Both Object.equals() and Object.hashCode() must be overridden
// for the correct operation of some connection managers
// -------------------------------------------------------------------
public boolean equals(Object obj) {
return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class));
}
public int hashCode() {
return EasySSLSocketFactory.class.hashCode();
}
}
And the TrustManager:
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
/**
* @author olamy
* @version $Id: EasyX509TrustManager.java 765355 2009-04-15 20:59:07Z evenisse $
* @since 1.2.3
*/
public class EasyX509TrustManager implements X509TrustManager {
private X509TrustManager standardTrustManager = null;
/**
* Constructor for EasyX509TrustManager.
*/
public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException {
super();
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init(keystore);
TrustManager[] trustmanagers = factory.getTrustManagers();
if (trustmanagers.length == 0) {
throw new NoSuchAlgorithmException("no trust manager found");
}
this.standardTrustManager = (X509TrustManager) trustmanagers[0];
}
/**
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
*/
public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
standardTrustManager.checkClientTrusted(certificates, authType);
}
/**
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)
*/
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
if ((certificates != null) && (certificates.length == 1)) {
certificates[0].checkValidity();
} else {
standardTrustManager.checkServerTrusted(certificates, authType);
}
}
/**
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
public X509Certificate[] getAcceptedIssuers() {
return this.standardTrustManager.getAcceptedIssuers();
}
}
(Both classes are from exchangeit with a small change on the EasySSLSocketFactory to work on android 2.2)
Now we have to do some other preparations and create a HttpClient that we can use to establish the connection:
//members private ClientConnectionManager clientConnectionManager; private HttpContext context; private HttpParams params;
//prepare for the https connection
//call this in the constructor of the class that does the connection if
//it's used multiple times
SchemeRegistry schemeRegistry = new SchemeRegistry();
// http scheme
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// https scheme
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
params = new BasicHttpParams();
params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 1);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(1));
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf8");
// ignore that the ssl cert is self signed
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope("yourServerHere.com", AuthScope.ANY_PORT),
new UsernamePasswordCredentials("YourUserNameHere", "UserPasswordHere"));
clientConnectionManager = new ThreadSafeClientConnManager(params, schemeRegistry);
context = new BasicHttpContext();
context.setAttribute("http.auth.credentials-provider", credentialsProvider);
}
//connection (client has to be created for every new connection)
client = new DefaultHttpClient(clientConnectionManager, params);
HttpGet get = new HttpGet("https://www.example.com/");
HttpResponse response = client.execute(get, context);
And that's it. I hope this will help some of you to solve their problems with self-signed certs!
android · cert · certificate · https · self-signed · ssl

