Unity实现EXE指定时间过期的问题及现有代码缺陷
Your code works for basic time-limited access, but the critical flaw is that PlayerPrefs stores data in an app-specific directory. When a user uninstalls your EXE, this directory gets deleted along with the app, so reinstalling lets them start fresh with a new 3-day window.
Here are a few practical solutions, ordered by ease of implementation and security:
Option 1: Store Expiry Data in a System-Wide Folder (Simple & Quick)
Save the first launch date to a public system folder (like the user's Documents directory) instead of the app's private storage. This file won't be deleted when the app is uninstalled, so reinstalls will pick up the original expiry date.
Updated Code Example:
using System.IO; using System; using UnityEngine; public class LocalLimitedDaysLicense : MonoBehaviour { public float numberOfDays = 3; private bool isShowExpiryMessage; // Use the user's Documents folder to store the license file private string LicenseFilePath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "MyApp_LicenseData.txt"); void Awake() { DateTime today = DateTime.Now; DateTime firstLaunchDate; // Check if the license file exists if (File.Exists(LicenseFilePath)) { string savedDateText = File.ReadAllText(LicenseFilePath); if (DateTime.TryParse(savedDateText, out firstLaunchDate)) { Debug.Log("Loaded existing first launch date"); } else { // File is corrupted - reset and save new date firstLaunchDate = today; File.WriteAllText(LicenseFilePath, firstLaunchDate.ToString()); Debug.Log("Corrupted license file - resetting launch date"); } } else { // First launch - save current date firstLaunchDate = today; File.WriteAllText(LicenseFilePath, firstLaunchDate.ToString()); Debug.Log("First launch - saved initial license date"); } // Check if app is expired DateTime expiryDate = firstLaunchDate.AddDays(numberOfDays); if (DateTime.Compare(today, expiryDate) > 0) { Time.timeScale = 0; isShowExpiryMessage = true; } // Block users from rolling back system time if (DateTime.Compare(today, firstLaunchDate) < 0) { Time.timeScale = 0; isShowExpiryMessage = true; } } void OnGUI() { if (isShowExpiryMessage) { GUI.Label(new Rect((Screen.width / 2) - 100, Screen.height / 2, 300, 100), "Sorry the exe has expired.!"); } } }
Note: Users can still manually delete the MyApp_LicenseData.txt file to reset the expiry, so this is best for low-security use cases.
Option 2: Tie Expiry to Hardware ID (Better Security)
Link the first launch date to a unique hardware identifier (like motherboard serial number, disk ID, or Unity's SystemInfo.deviceUniqueIdentifier). Store both the ID and date in a public location—this way, even if the user deletes the file, reinstalling on the same hardware will recognize the original expiry.
Example Hardware ID Retrieval:
private string GetUniqueHardwareId() { // Fall back to Unity's device ID if hardware reading fails string fallbackId = SystemInfo.deviceUniqueIdentifier; try { // Read disk serial number (Windows-only example) using (var searcher = new System.Management.ManagementObjectSearcher("SELECT SerialNumber FROM Win32_DiskDrive WHERE InterfaceType='IDE'")) { foreach (var obj in searcher.Get()) { string serial = obj["SerialNumber"]?.ToString(); if (!string.IsNullOrWhiteSpace(serial)) { return serial.Trim(); } } } } catch (Exception e) { Debug.LogError($"Failed to read hardware ID: {e.Message}"); } return fallbackId; }
Modify the storage logic to save a string like [HardwareID]|[FirstLaunchDate], then verify the hardware ID matches on each launch before checking the expiry date.
Option 3: Server-Side Validation (Highest Security)
If your app has internet access, the most tamper-proof method is to store license data (hardware ID + expiry date) on a backend server. On each launch, the app sends the hardware ID to the server, which returns whether the license is still valid. This eliminates local tampering entirely, but requires setting up a backend service.
Key Notes
- No local solution is 100% tamper-proof—determined users can reverse-engineer or modify files. These solutions just raise the bar for casual tampering.
- For Windows, you can also use the Windows Registry (e.g.,
HKEY_CURRENT_USER\Software\YourAppName) to store data, which works similarly to the public folder approach.
内容的提问来源于stack exchange,提问作者Muhammad Faizan Khan

