This section describes the points to note for developing a PSM application.
Contents
Pay attention to the following when using HTTP, Socket, or other APIs to access a mobile phone network.
- Do not download files that exceed 20 MB.
Currently, an API for obtaining whether the device is using Wi-Fi or a mobile phone network is not provided.
This API is scheduled to be added to future releases of the SDK.
For applications that connect to a network with PlayStation(R)Mobile Simulator, set proxy settings as required.
Select the "Connections" tab in "Internet Options" in the Control Panel, then set the "Proxy server" settings in "LAN settings".
Note that the value set for "Automatic configuration" will not be used by PlayStation(R)Mobile Simulator. To use a proxy, set "Proxy server".
Since PSM applications operate on a variety of platforms, make sure they can operate in both environments where case sensitivity applies (case-sensitive) for filenames and in environments where case sensitivity does not apply (case-insensitive).
In order for applications to operate in both environments, when coding make sure that the cases of filenames in code and filenames in storage match.
Example:
Attempting to load the file foo.txt in storage.
// A StreamReader r = new StreamReader("Foo.txt"); // B StreamReader r = new StreamReader("foo.txt");Both code examples will successfully load the file in a case-insensitive environment, but the loading of the file will fail with the code for "A" in a case-sensitive environment. Therefore, write a code like B where the cases match.
PSM applications may terminate without receiving any notification from the system.
Example: On a PS Vita, after pressing the PS button, a "peel" operation is performed.
Because of this, please implement applications so that safety can be maintained even if the execution of an application is suddenly interrupted.
When storing data, implementing one of the following methods will improve safety.
Write() of the StreamWriter and BinaryWriter cannot be terminated by the application's termination processing. As a result, either that data write fully completes, or data is not written at all.
Because of this, instead of calling Write() multiple times to write data, allocating data to buffers and then writing the data all at once will lessen the danger of creating incomplete data.
By following the procedure below to create new data to store, safety can be heightened.
- Create the target data as a temp file.
- After creation, use File.Move() to replace the temp file with the proper data to store.
PersistentMemory is a nonvolatile memory area that can be used by the application.
Because memory content stored to PersistentMemory will be reproduced automatically at the next application startup, it can be used (for example) to store details of application states while the application is running and reproduce the previous termination state upon the application's next startup.
However, in certain situations such as when an unexpected abnormal system termination occurs during application execution, content of PersistentMemory will be initialized. Thus, store important information - such as, an application's progress state - that will be problematic for the user when lost as save data under Documents/*.
When placing information dependent on save data to PersistentMemory, take measures against the loss of PersistentMemory by also storing the information in save data and synchronizing information of PersistentMemory and save data at appropriate timings such as application startup and during operation.
By maintaining the hash value in the stored data, data corruption can be detected during loading.
The following is an implementation example. Write/Read is performed for three ranking data and hash values.
using System.IO; ... const string SAVE_FILE = "/Documents/savedata.dat"; const string TEMP_FILE = "/Documents/temp.dat"; const Int32 numOfRanking=3; Int32[] ranking=new Int32[numOfRanking]; void SaveData() { Console.WriteLine("==SaveData()=="); ranking[0]=10000; ranking[1]=9000; ranking[2]=8000; int bufferSize=sizeof(Int32)* (numOfRanking+1); byte[] buffer = new byte[bufferSize]; Int32 sum=0; for(int i=0; i<numOfRanking; ++i) { Console.WriteLine("ranking[i]="+ranking[i]); Buffer.BlockCopy(ranking, sizeof(Int32)*i, buffer, sizeof(Int32)*i, sizeof(Int32)); sum+=ranking[i]; } Int32 hash=sum.GetHashCode(); Console.WriteLine("sum={0},hash={1}",sum,hash); Buffer.BlockCopy(BitConverter.GetBytes(hash), 0, buffer, numOfRanking * sizeof(Int32), sizeof(Int32)); using (System.IO.FileStream hStream = System.IO.File.Open(@TEMP_FILE, FileMode.Create)) { hStream.SetLength((int)bufferSize); hStream.Write(buffer, 0, (int)bufferSize); hStream.Close(); } if(File.Exists(@SAVE_FILE)) File.Delete(@SAVE_FILE); File.Move(@TEMP_FILE, @SAVE_FILE); } bool LoadData() { Console.WriteLine("==LoadData()=="); if ( System.IO.File.Exists(@SAVE_FILE)==false && System.IO.File.Exists(@TEMP_FILE)==true) { File.Move(@TEMP_FILE, @SAVE_FILE); } if ( System.IO.File.Exists(@SAVE_FILE)==true ) { using (System.IO.FileStream hStream = System.IO.File.Open(@SAVE_FILE, FileMode.Open)) { if (hStream != null) { long size = hStream.Length; byte[] buffer = new byte[size]; hStream.Read(buffer, 0, (int)size); Int32 sum=0; for(int i=0; i<numOfRanking; ++i) { Buffer.BlockCopy(buffer, sizeof(Int32)*i, ranking, sizeof(Int32)*i, sizeof(Int32)); Console.WriteLine("ranking[i]="+ranking[i]); sum+=ranking[i]; } Int32 hash=BitConverter.ToInt32( buffer, numOfRanking * sizeof(Int32) ); hStream.Close(); if(sum.GetHashCode()==hash) { Console.WriteLine("Correct Data."); return true; } else { Console.WriteLine("Incorrect Data."); return false; } } } } return false; }