These notes describe how to add support to your iOS app for retrieving Internet data via a Web service using the cross-platform, open-source Web Service Toolkit.
svn co https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/wst/trunk .Documentation is here: http://wiki.freepascal.org/Web_Service_Toolkit
fpc -Cirot -Fi../ -Fu../ -Fu../wst_rtti_filter -dWST_HANDLE_DOC ws_helper.pasNext parse the WSDL file for the Web service you want to use. For this example, we'll use a WSDL file from the U.S. National Weather Service. Download file ndfdXML.wsdl from this site:
http://www.usgovxml.com/DataService.aspx?ds=NDFD.
Parse ndfdXML.wsdl by entering the following all on one line (or put it in a script):
ws_helper -uA -p -o. -fhttp_graphical_weather_gov_xml_DWMLgen_schema_DWML_xsd=ndfdDWML_schema ndfdXML.wsdlFor more information about the various switches used, run ws_helper without any switches. The one switch that might require some explanation is the -f switch. It's used so that the name of one of the generated units is shortened to just ndfdDWML_schema.
With ndfdXML.wsdl, the ws_helper parser generates these files that you'll use along with the WST units:
ndfdXML.pas ndfdXML.wst ndfdXML_proxy.pas ndfdDWML_schema.pas
Indy Synapse ICS FPC's HTTP client Foundation framework-based HTTP client (for iOS)WST includes an xxxx_http_protocol.pas file for each library that implements two library-specific classes required by WST. You use the appropriate protocol unit along with the units generated from the Web service's WSDL file to call the Web service from your app.
To test on iOS, we'll use the NDFD Web service to retrieve a 5-day weather forecast for Silverton, Colorado, a town in the Rocky Mountains that generally has fairly cool nighttime temperatures because of its elevation (9,305 feet, or about 2,835 meters).
Create an iOS Pascal project in Xcode, then do the following:
SysUtils, DateUtils, ns_http_protocol, //WST units soap_formatter, base_service_intf, ndfdXML, //Web service units ndfdXML_proxy, ndfdDWML_schema
var NdfdService : ndfdXMLPortType; Latitude : Double; Longitude : Double; NumDays : Integer; StartDate : TDateRemotable; UnitsToUse : ndfdDWML_schema.unitType; begin NS_RegisterHTTP_Transport; try NdfdService := wst_CreateInstance_ndfdXMLPortType; if not Assigned(NdfdService) then WriteLn('Unable to connect to NDFD Web service.') else begin Latitude := 37.81; //Silverton, CO's lat/long Longitude := -107.66; NumDays := 5; StartDate := TDateRemotable.Create; StartDate.AsDate := Today; UnitsToUse := ndfdDWML_schema.e; //use ndfdDWML_schema.m for metric try WriteLn(NdfdService.NDFDgenByDay(Latitude, Longitude, StartDate, NumDays, UnitsToUse, formatType__24_hourly)); finally StartDate.Free; end; end; except on E:Exception do WriteLn(E.Message); end;
Naturally that means moving the WST-related code into its own unit and either wrapping it in a class or in a series of functions. In no case should this unit include VCL/LCL units like Forms, Dialogs, Controls, etc. in its uses statement.
The same goes for inputs to your WST-related code. For example, with the NDFD Web service, you would probably pass in the latitude and longitude rather than hard-wiring it the way we did for testing purposes. The NDFD Web service also provides methods for retrieving lat/long values for cities, zip codes, etc. You could wrap up these methods in a similar fashion.
{$IFDEF FPC} {$IF DEFINED(IPHONESIM) OR (DEFINED(DARWIN) AND DEFINED(CPUARM))} {iOS?} ns_http_protocol, {$ELSE} fpc_http_protocol, {$IFEND} {$ELSE} {Delphi} delphi_init_com, indy_http_protocol, {$ENDIF}Register the libraries conditionally in a similar fashion:
{$IFDEF FPC} {$IF DEFINED(IPHONESIM) OR (DEFINED(DARWIN) AND DEFINED(CPUARM))} NS_RegisterHTTP_Transport; {$ELSE} FPC_RegisterHTTP_Transport; {$IFEND} {$ELSE} INDY_RegisterHTTP_Transport; {$ENDIF}That's all you need to do. The rest of your WST-related code will be the same for all platforms.
Note that the NDFD methods return XML in a string. You could write this string to a temporary file, passing this file name back to the calling code, which then passes it on to your XML processing code. You could also write the XML string to a stream and pass the stream object back to the calling code. You can load either a file or a stream with the Free Pascal and Delphi XML parsers.
macpgmr (at) fastermac (dot) net
First posted Jan. 5, 2012; last edited May 9, 2013.