Check it out! Thanks
Yus' Blog
My rants and angst on iOS, MonoTouch, Android and things mobile
Sunday, March 27, 2016
Wednesday, August 22, 2012
App rejected because Apple uses sandbox account when testing
I encountered this about 2 weeks ago when my newsstand app was rejected by Apple because "in-app purchases weren't working". I was quite shocked at the time because I have tested everything rigorously and it was definitely working for me during my own testing. So after further investigation inspecting the server logs, I see the following errors:
INFO | Apple's response: {"status":21007}
The receipt status code of 21007 means "This receipt is a sandbox receipt, but it was sent to the production service for verification." You can see the complete list of auto-renewable verification status codes here. So it seems that when reviewing apps, apple could be using a sandbox iTunes account to purchase stuff in prod! This was something that I definitely did not expect and cater for in my production server code.
I wasn't 100% convinced about this but further research confirms this: "Always verify your receipt first with the production URL; proceed to verify with the sandbox URL if you receive a 21007 status code. Following this approach ensures that you do not have to switch between URLs while your application is being tested or reviewed in the sandbox or is live in the App Store.". You can see the full article here (faq #16).
That pretty much confirmed it. I was still quite bewildered that after 5 app approvals this is the first time that I have encountered this issue. I guess it depends on your luck what kind of tester you get when your app is being reviewed. Long story cut short the changes I made to my server code looks something like this:
I'm still not happy that I need to have a sandbox reference in my production code, but you just have to follow by Apple's rules. Hope this helps someone else!
INFO | Apple's response: {"status":21007}
The receipt status code of 21007 means "This receipt is a sandbox receipt, but it was sent to the production service for verification." You can see the complete list of auto-renewable verification status codes here. So it seems that when reviewing apps, apple could be using a sandbox iTunes account to purchase stuff in prod! This was something that I definitely did not expect and cater for in my production server code.
I wasn't 100% convinced about this but further research confirms this: "Always verify your receipt first with the production URL; proceed to verify with the sandbox URL if you receive a 21007 status code. Following this approach ensures that you do not have to switch between URLs while your application is being tested or reviewed in the sandbox or is live in the App Store.". You can see the full article here (faq #16).
That pretty much confirmed it. I was still quite bewildered that after 5 app approvals this is the first time that I have encountered this issue. I guess it depends on your luck what kind of tester you get when your app is being reviewed. Long story cut short the changes I made to my server code looks something like this:
public static Receipt GetReceipt(string receiptData) { const int SandboxReceiptSentToProd = 21007; var receipt = GetReceipt(urlProduction, receiptData); // GOTCHA: During apple approval, apple could be using a sandbox itunes account to purchase stuff in prod! // We have to check if receipt comes back with status 21007, that means the tester had used a sanbox account and // that we have to post the receipt to sandbox url instead of production if (receipt.Status == SandboxReceiptSentToProd) { // send receipt to sandbox now receipt = GetReceipt(urlSandbox, receiptData); } return receipt; }
I'm still not happy that I need to have a sandbox reference in my production code, but you just have to follow by Apple's rules. Hope this helps someone else!
Monday, August 20, 2012
CheckForIllegalCrossThreadCalls on MonoTouch 5.99
One of the first things I encountered after I upgraded to iOS6 (beta 4) and MonoTouch 5.99.2 was that my app would crash intermittently at random places. That got me quite worried, but a bit of googling reveals that this is because of a new feature in MonoTouch 6.0.
So the new version of MonoTouch will check for illegal cross thread calls and crash your app if its been naughty! The property UIApplication.CheckForIllegalCrossThreadCalls defaults to true for DEBUG ONLY. This is meant to educate the developers to fix the illegal cross thread calls.
So the new version of MonoTouch will check for illegal cross thread calls and crash your app if its been naughty! The property UIApplication.CheckForIllegalCrossThreadCalls defaults to true for DEBUG ONLY. This is meant to educate the developers to fix the illegal cross thread calls.
If you are after a quick fix, you can do this in your AppDelegate FinishedLaunching method:
public override void FinishedLaunching (UIApplication app) { UIApplication.CheckForIllegalCrossThreadCalls = false; // your other init code here ... }
However beware that the correct thing to do will be to fix your actual code!
Tuesday, August 7, 2012
iOS 6 Auto Rotate and Orientation Changes on MonoTouch 5.99 (alpha)
In iOS6, auto rotate and orientation changes have changed quite significantly.
In a nutshell, these are the steps I took to upgrade my monotouch project to work with the new changes:
1. You will need to assign a root view controller to your main application window on FinishedLaunching. This is the crucial bit! I spent quite sometime figuring this out. Basically if you don't set your root view controller, you will get a warning in build output that looks like this:
2. Replace this:
With these two lines:
public override bool ShouldAutorotate()
That's my experience in getting auto rotation to work in ios 6 on MonoTouch 5.99. Check out the full release notes in the developer portal or if you don't have a login, you can check it out here.
In a nutshell, these are the steps I took to upgrade my monotouch project to work with the new changes:
1. You will need to assign a root view controller to your main application window on FinishedLaunching. This is the crucial bit! I spent quite sometime figuring this out. Basically if you don't set your root view controller, you will get a warning in build output that looks like this:
Application windows are expected to have a root view controller at the end of application launch
So if previously like me you have this in your FinishedLaunching(UIApplication app) method in main.cs:
window.AddSubview(mainVC.View);
Replace it with this:
window.RootViewController = mainVC;
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
public override bool ShouldAutorotate()
public override UIInterfaceOrientationMask SupportedInterfaceOrientations()
Obviously you will need to specify the orientation masks your view controller support in SupportedInterfaceOrientstions(). For example, if you support all orientations you might want to do this:
public override bool ShouldAutorotate()
{
return true;
}
public override UIInterfaceOrientationMask SupportedInterfaceOrientations()
{
return UIInterfaceOrientationMask.All;
}
Thursday, May 3, 2012
Background Image Downloading with MonoTouch.Dialog ImageLoader
MonoTouch.Dialog contains a very useful class called ImageLoader to perform background image downloading like iTunes and AppStore.
ImageLoader does not have a DefaultImage property though which I need in my app to display as a placeholder before the actual image gets downloaded or if the download failed. You will need to do a little extra work to assign a default image.
First a little background on how ImageLoader works. ImageLoader caches downloaded images automatically (defaults to 50 images) so calling ImageLoader.DefaultRequestImage will either return a null if the image is not cached or the actual UIImage object if the image is cached. In the former case ImageLoader will queue a download request for the image and then call the interface method UpdatedImage when the download succeeds.
If the image is cached, your ImageView will display the real image. If it's not the default image will be displayed. In the UpdatedImage callback method, you should just do the following:
You can check the official doco here:
http://docs.xamarin.com/ios/tutorials/MonoTouch.Dialog#Background_Image_Loading
And the actual code for ImageLoader.cs can be found here:
https://github.com/migueldeicaza/MonoTouch.Dialog/blob/master/MonoTouch.Dialog/Utilities/ImageLoader.cs
ImageLoader does not have a DefaultImage property though which I need in my app to display as a placeholder before the actual image gets downloaded or if the download failed. You will need to do a little extra work to assign a default image.
First a little background on how ImageLoader works. ImageLoader caches downloaded images automatically (defaults to 50 images) so calling ImageLoader.DefaultRequestImage will either return a null if the image is not cached or the actual UIImage object if the image is cached. In the former case ImageLoader will queue a download request for the image and then call the interface method UpdatedImage when the download succeeds.
What happens when the download failed though? ImageLoader does NOT call UpdatedImage if the download failed. So you can't assign the your default image there because nothing will be done.
Instead, you should assign your default image immediately after the first call to DefaulRequestImage.
var cover = ImageLoader.DefaultRequestImage(uri, this);
if(cover == null)
{
_ImageView.Image = DefaultImage;
}
else
{
_ImageView.Image = cover;
}
#region IImageUpdated implementation
public void UpdatedImage (Uri uri)
{
_ImageView.Image = ImageLoader.DefaultRequestImage(uri, this);
}
#endregion
In the case where download succeeded, this will get called and your default image will be replaced with the real image. If download failed, this method won't get called and your default image stays.
I will post a full sample soon.
You can check the official doco here:
http://docs.xamarin.com/ios/tutorials/MonoTouch.Dialog#Background_Image_Loading
And the actual code for ImageLoader.cs can be found here:
https://github.com/migueldeicaza/MonoTouch.Dialog/blob/master/MonoTouch.Dialog/Utilities/ImageLoader.cs
Monday, April 23, 2012
Monotouch upload error after renaming output assembly
I discovered today the hard way that renaming your iOS project assembly in MonoDevelop under Project Options/Built/Output can result in the following error when you try to upload your app to your iOS device:
Installation failed: AMDeviceInstallApplication returned: 0xe8008001
The solution to this is make sure your output assembly is named the same as your application! For example if my application is called HelloWorld, then in your output folder you should have HelloWorld.app and HelloWorld.exe. If these two are not named the same then you will get the above error.
So lesson learnt.. don't be a smart arse renaming stuff that works!
Installation failed: AMDeviceInstallApplication returned: 0xe8008001
The solution to this is make sure your output assembly is named the same as your application! For example if my application is called HelloWorld, then in your output folder you should have HelloWorld.app and HelloWorld.exe. If these two are not named the same then you will get the above error.
So lesson learnt.. don't be a smart arse renaming stuff that works!
Saturday, March 31, 2012
Upgrade to Lion for MonoTouch users
These were the steps I took to upgrade from Snow Leopard to Lion to make MonoTouch work with ios sdk 5.1:
1. Install Lion.
2. Check system updates (will install 10.7.3 Lion update if you are not already on it. My usb stick that was purchased from apple store has 10.7.2).
3. Install XCode 4.3 from Mac AppStore (will require your apple login, and will give you the option to delete Xcode 4.2 which I did).
4. Check Monodevelop updates (will install 2.8.6.5 containing XCode 4.3 compatibility).
5. Re-install MonoTouch http://download.xamarin.com/Installer/Monotouch/monotouch-full.dmg This will download MonoTouch 5.2.5 (or whatever the latest version is when you read this blog).
6. Update Versions to latest version if you are using Versions for source control. I use Versions to connect to tfs using svnbridge. More info on svnbridge: http://svnbridge.codeplex.com/
7. Open terminal and run:
sudo xcode-select -switch /Applications/Xcode.app/
to set xcode path to make Versions work properly.
8. Install command tools from xcode/preferences/Downloads
Subscribe to:
Posts (Atom)