[Apple Store]restrict the locations

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

[Apple Store]restrict the locations

Postby Lena » Fri Nov 09, 2018 12:43 am

Hello.
A mobile application has been created for one of the pharmacies in the city of Denver USA. In addition to medical products, marijuana is sold there it is officially authorized. In the developer’s console apple I dropped all countries and left only the USA and Canada. In Canada official sale of marijuana is also permitted.
However, when I try to publish the application I get a refusal:
Guideline 1.4.3 - Safety - Physical Harm
Your app offers medicinal or recreational marijuana dispensary information, which is not legal in all of the locations where your app is available.
Next Steps
Please revise your app to restrict the locations where your app can be used.


I read this: CoreLocation
But I did not understand how to implement Next Steps on FMX for USA and Canada. Please tell me how to.
Lena
BCBJ Master
BCBJ Master
 
Posts: 596
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Fri Nov 09, 2018 12:58 pm

You are probably getting rejected because marijuana is not legalized in the entire USA, a few states still have not legalized it yet even for medical use (whereas marijuana is legal for both recreation and medicine in the entire Canada). So, limiting your app to the USA as a whole is likely a bit too broad for Apple's guidelines.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Mon Nov 12, 2018 2:19 am

Hi.
How to perform Next Steps?:
Guideline 1.4.3 - Safety - Physical Harm
Your app offers medicinal or recreational marijuana dispensary information, which is not legal in all of the locations where your app is available.
Next Steps
Please revise your app to restrict the locations where your app can be used.
Resources
For information on location awareness options, please review the https://developer.apple.com/library/arc ... ction.html available in the iOS Developer Center.
If you are interested in implementing geo-blocking, please review https://developer.apple.com/library/arc ... ation.html



How to determine if an application is running in Colorado? If not, disable launch.
FMX TGeocoder AdminArea? how to use?
Last edited by Lena on Tue Nov 13, 2018 3:00 am, edited 1 time in total.
Lena
BCBJ Master
BCBJ Master
 
Posts: 596
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Mon Nov 12, 2018 11:56 am

Lena wrote:What now? How to perform Next Steps?


I don't have an answer for that.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Thu Nov 15, 2018 12:59 am

Hi, rlebeau.
Help please find the problem in my code.
All breakpoints are normal.
However, the event OnGeocodeReverseEvent is not executed.
Code: Select all
//h file
#include <System.Sensors.Components.hpp>
#include <System.Sensors.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:   // IDE-managed Components
   TLocationSensor *LocationSensor1;
   TLabel *Label1;
   TLabel *Label2;
   TButton *Button1;
   TMemo *Memo1;
   TEdit *Edit1;
   TEdit *Edit2;
   TCheckBox *CheckBox1;
   void __fastcall LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
        const TLocationCoord2D &NewLocation);
   void __fastcall FormShow(TObject *Sender);
private:   // User declarations
    TGeocoder *fGeocoder;
public:      // User declarations
   __fastcall TForm1(TComponent* Owner);
   void __fastcall OnGeocodeReverseEvent(TCivicAddress* const Address);
};


Code: Select all
//cpp
//---------------------------------------------------------------------------

#include <fmx.h>
#pragma hdrstop

#include "geo.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
 LocationSensor1->Active=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
        const TLocationCoord2D &NewLocation)
{
   if (CheckBox1->IsChecked == true)
   {
     Edit1->Text = NewLocation.Latitude;
     Edit2->Text = NewLocation.Longitude;
   }

   try
    {
     if(fGeocoder == NULL)
      {
       if(TGeocoder::Current != NULL)
         {
         fGeocoder = (TGeocoder*)new TGeocoderClass(TGeocoder::Current);
           }

       if(fGeocoder != NULL)
         {
         fGeocoder->OnGeocodeReverse = OnGeocodeReverseEvent;// breakpoint OK
           }

      }

     if((fGeocoder != NULL) && (fGeocoder->Geocoding()))
       {
        fGeocoder->GeocodeReverse(NewLocation);
         }

    }
    catch (const Exception &E)
        {
         String MES =  E.Message;
         ShowMessage(L"Error: " + MES);
        }


}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
   CheckBox1->IsChecked=true;
}
//---------------------------------------------------------------------------
 void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {
    if (Address!= NULL)
    {
      Memo1->Lines->Add(Address->CountryName);
      Memo1->Lines->Add(Address->AdminArea);
    }
    /*
    if((Address->CountryName != "USA") &&(Address->AdminArea != "Colorado"))
    {
      ShowMessage(L"This app only for Colorado.");
      LocationSensor1->Active = false;
      Application->Terminate();
     }
     */
 }
Lena
BCBJ Master
BCBJ Master
 
Posts: 596
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Fri Nov 16, 2018 3:52 pm

Lena wrote:However, the event OnGeocodeReverseEvent is not executed.


That is probably because you are not actually calling GeocodeReverse() to perform a lookup, so there is no result to report. There is a bug in your code logic:

Code: Select all
if((fGeocoder != NULL) && (fGeocoder->Geocoding())) // <-- BUG!
    {
    fGeocoder->GeocodeReverse(NewLocation);
    }


It should look like this instead:

Code: Select all
if((fGeocoder != NULL) && (!fGeocoder->Geocoding())) // <-- FIXED
    {
    fGeocoder->GeocodeReverse(NewLocation);
    }


Notice the '!' operator when checking the result of Geocoding(). You want to call GeocodeReverse() when the Geocoder is NOT busy performing a reverse lookup.

Also, there is another bug in your code. In your OnGeocodeReverse handler, in the commented out code, you are using the '&&' operator where you should be using the '||' operator instead:

Code: Select all
if((Address->CountryName != "USA") &&(Address->AdminArea != "Colorado")) // <-- WRONG


If the location is within the USA, but anywhere other than Colorado, your app will not exit correctly. It will only exit if the location is not in the USA at all. You want the app to exit if the location is anywhere other than Colorado USA:

Code: Select all
if((Address->CountryName != "USA") || (Address->AdminArea != "Colorado")) // <-- FIXED


Alternatively, if you want to use '&&', you need to do this instead:

Code: Select all
if(!((Address->CountryName == "USA") && (Address->AdminArea == "Colorado")))
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Sat Nov 17, 2018 5:03 am

Thank You rlebeau very much! Everything works perfectly!

P.S.
My problem now is that I am in Ukraine and I don’t yet know how to change my new test code to see in Memo state of Colorado.
//Denver Colorado on google map: 39.739170, -104.984720
NewLocation.Latitude = 39.739170;
[bcciosarm64 Error] geo.cpp(25): read-only variable is not assignable

It is possible to see the force Сolorado in Memo if I'm in Ukraine? :)
I do not know what to write correctly in the operator Address->AdminArea ==
1. Colorado
2. State of Colorado
3. Colorado State
4. Colorado State of USA
etc.

May be it the best way:
Code: Select all
String s = Address->AdminArea;
int p = s.Pos("Colorado");
if(p>0)
  {
  //user in Сolorado
  //***
  }
  else
    {
     ShowMessage(L"This app only for Colorado.");
     LocationSensor1->Active = false;
     Application->Terminate();//is it correct for IOS?
    }

?
Lena
BCBJ Master
BCBJ Master
 
Posts: 596
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Mon Nov 19, 2018 2:25 pm

Lena wrote:My problem now is that I am in Ukraine and I don’t yet know how to change my new test code to see in Memo state of Colorado.


Simply call GeocodeReverse() with hard-coded coordinates instead of using the ones provided by the OnLocationChanged event.

Lena wrote:[bcciosarm64 Error] geo.cpp(25): read-only variable is not assignable


That is because the NewLocation parameter of the OnLocationChanged event is declared as const, so you can't change its member values. Simply use a local variable instead:

Code: Select all
TLocationCoord2D TestCoordinates;
TestCoordinates.Latitude = 39.739170;
TestCoordinates.Longitude = -104.984720;
fGeocoder->GeocodeReverse(TestCoordinates);
Last edited by rlebeau on Wed Nov 21, 2018 5:31 pm, edited 1 time in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Tue Nov 20, 2018 12:37 am

Thanks so much it works. In Memo, I received two lines but in russian:
Соединенные Штаты Америки
CO


Is it correct now for USA?
Code: Select all
void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {
    if (Address!= NULL)
    {
      //Memo1->Lines->Add(Address->CountryName);
      //Memo1->Lines->Add(Address->AdminArea);
      String state = Address->AdminArea;
      String country = Address->CountryName;

      bool checkcountry = false;
      int checkcountry_short = country.Pos("USA");
      int checkcountry_long = country.Pos("United States");
      if(checkcountry_short > 0 || checkcountry_long > 0)
       {
        checkcountry = true;
       }

      bool checkstate = false;
      int state_short = state.Pos("CO");
      int state_long = state.Pos("Colorado");
      if(state_short > 0 || state_long > 0)
       {
        checkstate = true;
       }


      if(checkcountry && checkstate)
        {
        //user in Сolorado
        //***
        }
        else
         {
          ShowMessage(L"This app only for Colorado.");
          LocationSensor1->Active = false;
          Application->Terminate();
         }
    }

 }


P.S.
There is still such a question. At the very first start of the application, a ios window appears asking the system to allow or not access to geodata. How to understand that the user pressed the button to ban, well, then close the application.
Lena
BCBJ Master
BCBJ Master
 
Posts: 596
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Wed Nov 21, 2018 5:54 pm

Lena wrote:In Memo, I received two lines but in russian:
Соединенные Штаты Америки
CO



"Соединенные Штаты Америки" is Russian for "United States of America" (according to Google Translate). Kind of odd that you receive USA in Russian in that way. I suppose you will have to account for that, unless you can somehow request the result to be in English only. It looks like iOS's Geocoder API has a "preferredLocale" parameter for that purpose, but Embarcadero's TGeocoder class does not expose access to that. So you might need to use the API directly instead of Embarcadero's wrapper.

"CO" is the correct state abbreviation for Colorado, though.

Lena wrote:
Code: Select all
int checkcountry_short = country.Pos("USA");


I would not use Pos() for that check, I would use operator== (case sensitive) or SameText() (case insensitive) instead. You should be comparing the complete country code, not a portion of it.

Lena wrote:
Code: Select all
int state_short = state.Pos("CO");


Same here, too.

Lena wrote:
Code: Select all
ShowMessage(L"This app only for Colorado.");


I would suggest including USA in that text message, just to make it clear to the user:

Code: Select all
ShowMessage(L"This app only for Colorado, USA.");


Lena wrote:At the very first start of the application, a ios window appears asking the system to allow or not access to geodata. How to understand that the user pressed the button to ban, well, then close the application.


iOS has an API for that (see Choosing the Authorization Level for Location Services), but I don't know how to utilize that in C++Builder. You will likely have to access iOS's CLLocationManager API directly for that.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Mon Nov 26, 2018 5:18 am

I would not use Pos() for that check, I would use operator== (case sensitive) or SameText() (case insensitive) instead.


Is it correct now?
Code: Select all
 void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {

    if (Address != NULL)
    {
      //Memo1->Lines->Clear();
      Memo1->Lines->Add(Address->CountryName);
      Memo1->Lines->Add(Address->AdminArea);

      bool checkcountry = false;
      bool checkcountry_short = SameText(Address->AdminArea, L"USA");
      bool checkcountry_long = SameText(Address->AdminArea, L"United States of America");
      if(checkcountry_short || checkcountry_long)
       {
        checkcountry = true;
       }

      bool checkstate = false;
      bool state_short = SameText(Address->CountryName, L"CO");
      bool state_long = SameText(Address->CountryName, L"Colorado");
      if(state_short || state_long )
       {
        checkstate = true;
       }

      if(checkcountry && checkstate)
        {
         //user in Сolorado
         ShowMessage(L"Welcome. You are in the state of Colorado USA.");
        }
        else
         {
          ShowMessage(L"Sorry this app is only for the state of Colorado USA.");
          LocationSensor1->Active = false;
          //Halt(0);
          //Close();
          //Application->Terminate();
         }

    }

 }
Lena
BCBJ Master
BCBJ Master
 
Posts: 596
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Mon Nov 26, 2018 2:51 pm

Lena wrote:Is it correct now?


No (and why aren't you testing this stuff yourself? You have coordinates for Colorado, why aren't you running it to see what the actual output is?).

You have reversed the logic to look for the Country code in the AdminArea, and the State code in the CountryCode.

Try this:

Code: Select all
void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
{
    if (!Address) return;

    String country = Address->CountryName;
    String state = Address->AdminArea;

    //Memo1->Lines->Clear();
    Memo1->Lines->Add(country);
    Memo1->Lines->Add(state);

    bool checkcountry = SameText(country, L"USA") ||
                        SameText(country, L"United States of America");

    bool checkstate = SameText(state, L"CO") ||
                      SameText(state, L"Colorado");

    if (checkcountry && checkstate)
    {
        //user in Сolorado
        ShowMessage(L"Welcome. You are in the state of Colorado USA.");
    }
    else
    {
        ShowMessage(L"Sorry this app is only for the state of Colorado USA.");
        LocationSensor1->Active = false;
        //Halt(0);
        //Application->Terminate();
        Close();
    }
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Tue Nov 27, 2018 7:06 am

and why aren't you testing this stuff yourself? You have coordinates for Colorado, why aren't you running it to see what the actual output is?


To test my application (I'm in Ukraine), I take the iphone from my friend. In his iphone I get coordinates in Russian:
Соединенные Штаты Америки
СO

Do I need to delete a friend’s account from his iphone to see the coordinates in English?

Code: Select all
 void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
 {

if (!Address) return;

   String country = Address->CountryName;
   String state = Address->AdminArea;

   //Memo1->Lines->Clear();
   Memo1->Lines->Add(country);
   Memo1->Lines->Add(state);

   bool checkcountry = SameText(country, L"USA") ||
                  SameText(country, L"United States of America");

   bool checkstate = SameText(state, L"CO") ||
                 SameText(state, L"Colorado");

   if (checkcountry && checkstate)
   {
      //user in Сolorado
      ShowMessage(L"Welcome. You are in the state of Colorado USA.");
   }
   else
   {
      ShowMessage(L"Sorry this app is only for the state of Colorado USA.");
      LocationSensor1->Active = false;
      Close();
   }

 }


I satrt my application from IDE. On the iphone, I see the window "Allow access to geodata?". I click "Allow" and get error:
First chance exception at $0000000100D08940. Exception class EUnsupportedPlatformService with message 'Unsupported platform service: Terminate'. Process geoios (1274)

And I fall into a file FMX.Platform.IOS:
Code: Select all
procedure TPlatformCocoaTouch.Terminate;
begin
  FTerminating := True;
  FRunning := False;
  TMessageManager.DefaultManager.SendMessage(nil, TApplicationTerminatingMessage.Create);
  raise EUnsupportedPlatformService.CreateFMT(SUnsupportedPlatformService, ['Terminate']); //<----HERE
end;


If I comment Close() no error and I see ShowMessage "Sorry this app is only for the state of Colorado USA."
Lena
BCBJ Master
BCBJ Master
 
Posts: 596
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Apple Store]restrict the locations

Postby rlebeau » Tue Nov 27, 2018 12:43 pm

Lena wrote:To test my application (I'm in Ukraine), I take the iphone from my friend. In his iphone I get coordinates in Russian:
Соединенные Штаты Америки
СO

Do I need to delete a friend’s account from his iphone to see the coordinates in English?


I already addressed that in an earlier reply:

"Соединенные Штаты Америки" is Russian for "United States of America" (according to Google Translate). Kind of odd that you receive USA in Russian in that way. I suppose you will have to account for that, unless you can somehow request the result to be in English only. It looks like iOS's Geocoder API has a "preferredLocale" parameter for that purpose, but Embarcadero's TGeocoder class does not expose access to that. So you might need to use the API directly instead of Embarcadero's wrapper.


You should file a feature request with Embarcadero to add locale support to TGeocoder. In the meantime, the simplest workaround would be to just add "Соединенные Штаты Америки" to the list of country codes you check for:

Code: Select all
bool checkcountry = SameText(country, L"USA") ||
               SameText(country, L"United States of America") ||
               SameText(country, L"Соединенные Штаты Америки");


But then, you might need to do the same thing for every possible language that your app may run under (French? Spanish? etc). That could get a bit tedious, to say the least.

Lena wrote:I satrt my application from IDE. On the iphone, I see the window "Allow access to geodata?". I click "Allow" and get error:
First chance exception at $0000000100D08940. Exception class EUnsupportedPlatformService with message 'Unsupported platform service: Terminate'. Process geoios (1274)

And I fall into a file FMX.Platform.IOS:
Code: Select all
procedure TPlatformCocoaTouch.Terminate;
begin
  FTerminating := True;
  FRunning := False;
  TMessageManager.DefaultManager.SendMessage(nil, TApplicationTerminatingMessage.Create);
  raise EUnsupportedPlatformService.CreateFMT(SUnsupportedPlatformService, ['Terminate']); //<----HERE
end;



Looks like you are not the only person to encounter that, see What is the proper way to terminate an iOS app?.

Per Proper way to exit iPhone application, apparently iOS apps are NOT SUPPOSED to exit themselves, they simply get sent to the background when the user closes them.

So, you will have to avoid calling Application->Terminate(), and also Close()'ing the MainForm. You will likely have to redesign your UI logic to simply block access to whatever functionality is location-specific, without actually exiting the app. Per Apple's guidelines:

Q: How do I programmatically quit my iOS application?

There is no API provided for gracefully terminating an iOS application.

In iOS, the user presses the Home button to close applications. Should your application have conditions in which it cannot provide its intended function, the recommended approach is to display an alert for the user that indicates the nature of the problem and possible actions the user could take — turning on WiFi, enabling Location Services, etc. Allow the user to terminate the application at their own discretion.
...


Lena wrote:If I comment Close() no error and I see ShowMessage "Sorry this app is only for the state of Colorado USA."


Makes sense, since your code is not checking for the Russian encoding of "United States of America".
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Apple Store]restrict the locations

Postby Lena » Wed Nov 28, 2018 2:19 am

Thank You!

to simply block access to whatever functionality is location-specific, without actually exiting the app


Very good idea!
I think I add a display of the new TForm. In label write "Sorry this app is only for the state of Colorado USA. Restart this application completely when you are in the state of Colorado USA."
No more interface elements on this form.
Code: Select all
else
    {
         LocationSensor1->Active = false;
         MyNewForm->Show();
        //Halt(0);
        //Application->Terminate();
        //Close();
    }

Lena
BCBJ Master
BCBJ Master
 
Posts: 596
Joined: Sun Feb 06, 2011 1:28 pm

Next

Return to Technical

Who is online

Users browsing this forum: No registered users and 14 guests