如何找出自 iOS 应用程序被特定 user/device 首次打开以来已经过去了多少天?

How to find out how many days have passed since an iOS app was opened the first time by a specific user/device?

我创建了一个 iOS 应用程序,并希望让用户有机会在安装该应用程序 并启动 后的 30 天内免费使用该应用程序第一次.

在这 30 天之后,我想关闭大部分功能。保留全部功能的唯一方法是使用用户名和密码登录,用户可以在专用网站上注册。

我的问题是:

当应用程序第一次启动时,我想在远程服务器上存储一个唯一标识符和这一刻的时间戳。然后我会知道这个唯一 ID 什么时候过去了 30 天。

不幸的是,iOS 上唯一类似 uuid 的标识符似乎是 identifierForVendor。根据文档,当用户删除来自同一应用程序供应商的所有应用程序然后重新安装它们时,uuid 会发生变化。由于此 uuid 与我存储在远程服务器数据库中的 uuid 不匹配,因此尽管 30 天过去了,用户仍可以重新使用该应用程序。

来自文档:

The uuid on iOS uses the identifierForVendor property. It is unique to the device across the same vendor, but will be different for different vendors and will change if all apps from the vendor are deleted and then reinstalled. See the official Apple docs.

The UUID will be the same if app is restored from a backup or iCloud as it is saved in preferences. Users using older versions of this plugin will still receive the same previous UUID generated by another means as it will be retrieved from preferences.

我的问题是:

有没有办法找出自用户第一次打开应用程序以来已经过去了多少天,即使他 deletes/reinstalls 所有应用程序都是我制作的?

注意: 因为我使用的是 Phonegap/Cordova,所以欢迎使用与 Cordova 兼容的解决方案,但原生 Swift/Objective-C 解决方案也可以。

您的应用程序可以在 iOS 设备的钥匙串中存储它自己的唯一 ID(来自服务器或可能随机生成)and/or 日期戳。从设备中删除应用程序时不会清除钥匙串。

参见 Apple 的 Keychain services programming guide

NSUbiquitousKeyValueStore 怎么样?

//    Use `NSUbiquitousKeyValueStore`     
    let iCloudKeyStore: NSUbiquitousKeyValueStore? = NSUbiquitousKeyValueStore()
    let isMyAppInstalled = true
    iCloudKeyStore?.setBool(isMyAppInstalled, forKey: "isMyAppInstalled")
    iCloudKeyStore?.synchronize()

如果您可以创建一个 web 服务来捕获并在 Sqlite 上存储设备 ID table,这里是解决方案:

您可以这样获取设备 ID:

  let DID = UIDevice.currentDevice().identifierForVendor!.UUIDString
    print("Device ID is : \(DID)")

然后像这样将此 ID 发送到您的 webSerivce: 在 AppDelegate 上放这个:

    internal static var DeviceList:[StructID] = []

然后创建一个名为 StructID 的 Swift Class,如下所示:

import Foundation


class StructID{
    internal var id:Int!
    internal var DevieID:String!
    internal var AllowInstall:String!
    internal var InstalledTime:String!
    internal var InstallCount:String!
}

然后在您的 FirstViewController 上您可以发送和存储许多数据,包括有多少这个 ID 安装了这个应用程序,或者第一次安装是什么时候,或者这个 ID 是否允许使用这个应用程序?或者你想要的任何东西!

 let IDs = StructID()
    IDs.DevieID = DID
    IDs.AllowInstall = AllowInstall // <declare it yourself
    IDs.InstalledTime = InstalledTime // <declare it yourself
    IDs.InstallCount = InstallCount // <declare it yourself


    var dictionary = Dictionary<String, AnyObject>()
    dictionary["id"] = IDs.id
    dictionary["DevieID"] = IDs.DevieID
    dictionary["AllowInstall"] = IDs.AllowInstall
    dictionary["InstalledTime"] = IDs.InstalledTime
    dictionary["InstallCount"] = IDs.InstallCount



 let url = NSURL(string: "http://www.YourWebAddress.com/service.php?action=insert")
    let session = NSURLSession.sharedSession()

        let request = NSMutableURLRequest(URL: url!)
        request.HTTPMethod = "POST"
        request.timeoutInterval = NSTimeInterval(10)
        do {
            let jsonData =  try NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions(rawValue: 0))
            request.HTTPBody = jsonData
        } catch {
            print("json data error")
        }
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")

        let task = session.dataTaskWithRequest(request) { (NSData, response, error) -> Void in
            let id = String (data: NSData!, encoding: NSUTF8StringEncoding)
            DeviceList.id = Int(id!) // <= its id column of your table
 AppDelegate.DeviceList.append(IDs) // <= it the Device id Your are sending
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.navigationController?.popToRootViewControllerAnimated(true)
            })
        }
        task.resume()
       }

和您的网络服务上的 php 代码:

 function getConnection () {
        $servername = "localhost";
        $username = "YourDatabseName_db";
        $password = "Password";
        $dbname = "YourDatabseName_db";

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    if ($conn->connect_error) {
        die("Connection failed: " . $conn->connect_error);
    }
    return $conn;
}

 $action = $_GET["action"];



if ($action == "insert") {
    $conn = getConnection();
    $jsonString = file_get_contents('php://input');
    $data = json_decode($jsonString, true);
    $DeviceID = $data["DeviceID"];
    $AllowInstall = $data["AllowInstall"];
    $InstalledTime = $data["InstalledTime"];
    $InstallCount = $data["InstallCount"];


    $sql = "INSERT INTO `YourDatabase_db`.`YourTableName` (`DeviceID`, `AllowInstall`, `InstalledTime `, `InstallCount `) VALUES ('$DeviceID', '$AllowInstall', '$InstalledTime', '$InstallCount')";
    if (mysqli_query($conn, $sql)){
        $last_id = mysqli_insert_id($conn);
        echo $last_id;
    } else {
        echo "Error: " . $sql . "<br>" . mysqli_error($conn);
    }

最后,当您的应用程序每次都加星时,您可以检查所有条件并做任何您想做的事...

为了阅读从 php 回来把它放在你的网络服务上 php :

if ($action == "selectgeneral") {
        $conn = getConnection();
               $sql = "SELECT * FROM yourtablename";

        $result = $conn->query($sql);
        $output = array();
        if ($result->num_rows > 0) {
            while($row = $result->fetch_assoc()) {
                $record = array();
                $record["id"] = $row["id"];
                $record["DevieID"] = $row["DevieID"];
                $record["AllowInstall"] = $row["AllowInstall"];
                $record["InstalledTime"] = $row["InstalledTime"];
                $record["InstallCount"] = $row["InstallCount"];
                array_push($output, $record);
            }
        } else {
            echo "0 results";
        }
        $conn->close();
        echo json_encode($output);

如果您想从 php 中读取数据:

 let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithURL(url) {(NSData, response, error) -> Void in
        do {
            let records = try NSJSONSerialization.JSONObjectWithData(NSData!, options: NSJSONReadingOptions.MutableContainers) as! NSArray

            for record in records {
                let record = StructID()
                record.id = Int(record["id"] as! String)
                record.DevieID = record["DevieID"] as! String
                record. AllowInstall = record["AllowInstall"] as! String
                record.InstalledTime = Int(record["InstalledTime"] as! String)
                record.InstallCount = Int(record["InstallCount"] as! String)


                AppDelegate.DeviceID.append(record)
            }
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.tableViewNote.reloadData()
            })
        }
        catch {
            print("Json Error")
        }
    }
    task.resume()

抱歉有点复杂。