Hello, thanks to all the great minds we've figured out how to deploy MZ/MV project to iOS devices.
I especially would like to thank
- MiltonSSR for kicking off the discussion
- BreakerZerofor giving me hints on initial steps
- HoofedEarfor many many many tests with me
-yymessfor solving the tap issue
Now for the actual program!
Prerequisites:
You will need a RPG Maker MZ/MV project, a Mac, an iOS device, and xcode 12. The process is tad different for xcode 11. If you absolutely have to use xcode 11, please refer to the original threads.
Also, be sure to get yourself an Apple Developer signing certificate if you want to test or distribute on actual iOS devices.
Process: Step 1: Export your game
Under File menu, select Deployment. Make sure to use Web as the platform
Step 2: Open xcode 12, and create a new project
For template, select iOS from the top, and App from Application section.
Spoiler: detailed settings
Enter your product name (we use newmzproj as an example)
Select your Apple Developer ID for Team
For Organization Identifier, enter your own domain name (if you have any) in reverse. For example, if I have iloverpgmaker.com, I would enter com.iloverpgmaker
This will create unique identifier for you - so make sure you use something unique to YOU.
For Interface, select [Storyboard]
For Life Cycle, select [UIKit App Delegate]
Language, [Swift]
You can untick Include Tests
Could tick Use Core Data but needs further investigation/understanding**
RPG Maker uses localforage to store data when running under iOS
I am not sure if the locally stored data will be persistent after an App update
Step 3: Modify the code and create a WKWebView
Once you have your project created, you should see ViewController.swift on left panel. Open the file.
There should be around 20 or so lines of codes. Replace with following codes.
Spoiler: swift code
Swift:
// // ViewController.swift // // https://forums.rpgmakerweb.com/index.php?threads/ios-app-creation-tutorial-for-mz-mv-xcode-12.128674/ import UIKit // Add WebKit import WebKit // Add WKNavigationDelegate, WKUIDelegate for navigation and ui delegation class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate { var webView: WKWebView! // This gets called when loading the WKWebView override func loadView() { super.loadView() webView = WKWebView() let webViewConfig = WKWebViewConfiguration() webViewConfig.dataDetectorTypes = [] webViewConfig.allowsInlineMediaPlayback = true webViewConfig.mediaTypesRequiringUserActionForPlayback = [] webView = WKWebView(frame: view.frame, configuration: webViewConfig) webView.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs") } // Called after the WebView was created override func viewDidLoad() { super.viewDidLoad() let htmlPath = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "www")! webView.loadFileURL(htmlPath, allowingReadAccessTo: htmlPath) webView.navigationDelegate = self webView.uiDelegate = self view = webView } // This is to allow JavaScript Alert() for debugging func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { // alert let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert) let action = UIAlertAction(title: "OK", style: .default) { _ in completionHandler() } alertController.addAction(action) present(alertController, animated: true, completion: nil) } }
Step 4: Import MZ/MV game
Right click the ViewControllwer.swift on the left panel
Select Add Files to "newmzproj"... from the menu
Select your games www folder and hit Add
Make sure to tick Copy items if needed
Select Create folder references
Your www folder should be same level as ViewController.swift file
Step 5: Allow MZ to start without focus (can skip for MV projects)
From left panel, navigate to www > js > rmmz_managers.js
Around line 2107, there should be SceneManager.isGameActive function. Modify the code to skip the check on focus.
Spoiler: scenemanager
JavaScript:
SceneManager.isGameActive = function() { return true; // [Note] We use "window.top" to support an iframe. try { return window.top.document.hasFocus(); } catch (e) { // SecurityError return true; } };