Local storage not working on iOS device


#1

Hi,
I am using local storage in my application, which works very well on the browser and on the android device, but it is not working on iOS device.

Below is the code .
First page for setting data

this.storage.set('userData', {
          userName: response.userName,
          userId: response.userId,
          adminId: response.adminId,
          adminName: response.adminName,
          roleId: response.roleId,
          roleName: response.roleName,
          action: response.action,
          adminRoleName:response.adminRoleName
        });

Second page for getting the data.

getLocalData() {
    this.storage.get('userData').then((data) => {
      this.userId = data.userId;
      this.roleName = data.roleName;
      this.action = data.action;
      console.log("userId ", this.userId);
    })
  }

Data is set on button click in the first page and the getLocalData() method is called in the constructor of the second page. But when running on iOS device this method is not called, so I am not able to get the details. I have debugged using the safari dev tools, but no success so far.


#2

Would need to see a complete repo to be certain, but my initial suspicion is a race condition whereby you try to read before the write has completed.


#3

Here is the code for two page where I am setting and getting the local data.

Login Page.

export class LoginUserPage {

  userId: string = "";
  userName: string;
  email: string = "";
  password: string = "";
  url: string;
  userList = [];
  filteredList = []

constructor(private navController: NavController, platform: Platform, public toastCtrl: ToastController, public storage: Storage,private httpSer: HttpCommonService,public viewCtrl: ViewController) {

  }

loginUser() {

this.filteredList = this.userList.filter(function (el) {
  return el.userName.toLowerCase().indexOf(this.userId.toLowerCase()) > -1;
}.bind(this));
if (this.filteredList.length > 0) {
  this.url = "xyz/" + this.filteredList[0].userId;
  this.httpSer.performGET(this.url).subscribe(
    response => {
      if (response.success) {
        this.navController.setRoot(DashboardPage);
        this.showToast("Welcome " + response.userName);
        this.storage.set('userData', {
          userName: response.userName,
          userId: this.filteredList[0].userId,
          adminId: response.adminId,
          adminName: response.adminName,
          roleId: response.roleId,
          roleName: response.roleName,
          action: response.action,
          adminRoleName:response.adminRoleName
        });
      }

    },
  );
} else {
  this.showToast("Please check username");
}
}
}

and in the dashboard page

declare var cordova: any;
declare var window: any;

@Component({
  selector: 'page-dashboard',
  templateUrl: 'dashboard.html',
  providers: [DatePipe]
})
export class DashboardPage {

constructor(public navCtrl: NavController, public navParams: NavParams, public modalCtrl: ModalController, public toastCtrl: ToastController,
    public alertCtrl: AlertController, private platform: Platform, private datePipe: DatePipe, private storage: Storage, private httpSer: HttpCommonService,
    public loadingCtrl: LoadingController) {

    this.platform = platform;
    this.alertCtrl = alertCtrl;
    this.rootPage = DashboardPage;
    this.storage = storage;
    this.getLocalData();

    this.platform.registerBackButtonAction(() => {
    this.platform.exitApp();
    });

    this.platform.ready().then(() => {
      debugger;
      if (this.platform.is('ios')) {
        this.storageDirectory = cordova.file.documentsDirectory;
        console.log("Dashboard page");
      }
      else if (this.platform.is('android')) {
        this.storageDirectory = cordova.file.externalDataDirectory;
      }
      else {
        return false;
      }
    });
  
  }

getLocalData() {
    console.log("A");
    this.storage.get('userData').then((data) => {
      this.userId = data.userId;
      this.roleName = data.roleName;
      this.action = data.action;
      console.log("userId ", this.userId);
    })
  }
}

Now as above, in login page after I get user details from back end web service I am setting the data in local storage, and in the dashboard page I am getting the local data in ```getLocalData()`` method. On android device it is working perfectly, but on iOS device I am unable to get the data, rather the data is getting stored locally I don’t know.


#4

I would put 2 function storeUser() and getUser() into the same provider UserService like belows
Then add UserService to the constructor of any pages required.
It works for both IOS, Android and web

import {Storage} from '@ionic/storage';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class UserService {
 constructor(private storage: Storage){}
 
public storeUser(userData): void {
     this.storage.set('userData', userData);
}

public getUser(): Observable<any>
  return Observable.fromPromise(this.storage.get('userData').then((val) => {
            return !!val;
        }));
}

#5

My problem is I am facing this issue on iOS device, local storage works fine on android and browser for me. @nguyenhuynh is local storage working on iOS device for you?


#6

Yes, it is working for both of them.


#7

Hi,
did you manage to solve this problem?
I’m too stuck with the storage on iOS devices.
Cannot see the values saved in the safari dev-tools.
Works fine on chrome and on an andorid device…


#8

@janein Yes, its working on both platforms for me. No need to do anything special for iOS platform, please debug your app, check your application flow, print data before and after saving in local storage.

All the best.


#9

Thanks but I still can’t find the issue.
Debugging through the app I can see, that the correct values are available at the time of saving.
And my syntax is exactly the same as yours above.
For some reason it’s just not working on iOS.


#10

Well if you post some code , then I might be able decode the problem.


#11
private storageKeys = {
    userData: 'userData'
};

constructor(
    public storage: Storage
  ) { ... }

saveUserData(userData) {
  let userData = { 'foo': 'bar' }; // also tested with a simple string
  this.storage.set(this.storageKeys.userData, userData);
}

No error gets thrown, but also no local storage is showing up in the safari dev-tools when debugging on an iphone.

Thanks for your help!

EDIT: I just tested it out in another provider - it works fiine there. Looks like it’s normal, that there is no local storage in the dev-tools. I’ll try to digg deeper - it already worked, so there must be a little evil bug in my code :wink:


#12

Your code seems okay, well you Know I am also a budding Ionic developer, so I wont be able to tell you the exact problem, for me I did not change any of my code, and it is working for me. Yeah as you said, it might be little bug, but eventually it will work.

All the best.


#13

Thanks,

I didn’t do any changes to my code and it suddenly worked.
I guess I was too focussed to see the saved values in the dev-tools, I forgot to check if there are any values being returned when getting from the storage.
My last commit saved my original issue and I didn’ see it :see_no_evil:

Thank you for your patience! :slight_smile:


#14

I hope I have the same luck you did…I am having the same issue on ios only (it works on the browser and on android)!


#15

It does indeed appear to be a race condition. You are not ensuring that anything has been written to storage at the time you try to read from it.

A couple of general things: storage is only a good fit here if you need to persist the data across app restarts. If you don’t, a shared service is a better option, and is easier to synchronize because you do it all in the service. Additionally, a lot of the information here looks related to authorization. Please make sure that all the serious security is done by the backend itself; do not trust the client-side app at all.