├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ ├── bob.yml │ └── trigger-site-rebuild.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── example_image.png └── index.md ├── example ├── imgs │ └── logo.png ├── main.collection ├── review.atlas ├── review.font └── timer.script ├── game.project ├── input └── game.input_binding └── review ├── api └── api.script_api ├── ext.manifest ├── manifests └── android │ └── build.gradle └── src ├── android ├── ReviewAndroid.cpp ├── java │ └── com │ │ └── defold │ │ └── review │ │ └── Review.java └── jni.h ├── ios └── ReviewIOS.mm ├── private_review.h └── review.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Defold Protocol Buffer Text Files (https://github.com/github/linguist/issues/5091) 2 | *.animationset linguist-language=JSON5 3 | *.atlas linguist-language=JSON5 4 | *.camera linguist-language=JSON5 5 | *.collection linguist-language=JSON5 6 | *.collectionfactory linguist-language=JSON5 7 | *.collectionproxy linguist-language=JSON5 8 | *.collisionobject linguist-language=JSON5 9 | *.cubemap linguist-language=JSON5 10 | *.display_profiles linguist-language=JSON5 11 | *.factory linguist-language=JSON5 12 | *.font linguist-language=JSON5 13 | *.gamepads linguist-language=JSON5 14 | *.go linguist-language=JSON5 15 | *.gui linguist-language=JSON5 16 | *.input_binding linguist-language=JSON5 17 | *.label linguist-language=JSON5 18 | *.material linguist-language=JSON5 19 | *.mesh linguist-language=JSON5 20 | *.model linguist-language=JSON5 21 | *.particlefx linguist-language=JSON5 22 | *.render linguist-language=JSON5 23 | *.sound linguist-language=JSON5 24 | *.sprite linguist-language=JSON5 25 | *.spinemodel linguist-language=JSON5 26 | *.spinescene linguist-language=JSON5 27 | *.texture_profiles linguist-language=JSON5 28 | *.tilemap linguist-language=JSON5 29 | *.tilesource linguist-language=JSON5 30 | 31 | # Defold JSON Files 32 | *.buffer linguist-language=JSON 33 | 34 | # Defold GLSL Shaders 35 | *.fp linguist-language=GLSL 36 | *.vp linguist-language=GLSL 37 | 38 | # Defold Lua Files 39 | *.editor_script linguist-language=Lua 40 | *.render_script linguist-language=Lua 41 | *.script linguist-language=Lua 42 | *.gui_script linguist-language=Lua 43 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: defold 2 | patreon: Defold 3 | custom: ['https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=NBNBHTUW4GS4C'] 4 | -------------------------------------------------------------------------------- /.github/workflows/bob.yml: -------------------------------------------------------------------------------- 1 | name: Build with bob 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | uses: defold/github-actions-common/.github/workflows/bob.yml@master 8 | -------------------------------------------------------------------------------- /.github/workflows/trigger-site-rebuild.yml: -------------------------------------------------------------------------------- 1 | name: Trigger site rebuild 2 | 3 | on: [push] 4 | 5 | jobs: 6 | site-rebuild: 7 | runs-on: ubuntu-latest 8 | 9 | steps: [ 10 | { 11 | name: 'Repository dispatch', 12 | uses: defold/repository-dispatch@1.2.1, 13 | with: { 14 | repo: 'defold/defold.github.io', 15 | token: '${{ secrets.SERVICES_GITHUB_TOKEN }}', 16 | user: 'services@defold.se', 17 | action: 'extension-review' 18 | } 19 | }] 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /.internal/ 3 | /.internal 4 | /build 5 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Alexey Gulev 4 | Copyright (c) 2020 The Defold Foundation 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Actions Status Alpha](https://github.com/defold/extension-review/actions/workflows/bob.yml/badge.svg)](https://github.com/defold/extension-review/actions) 2 | 3 | # Native iOS and Android ratings and review windows for Defold 4 | 5 | Defold [native extension](https://www.defold.com/manuals/extensions/) which allows the use of [native iOS Ratings and Reviews window](https://developer.apple.com/ios/human-interface-guidelines/system-capabilities/ratings-and-reviews/) and [Google Play In-App Review API](https://developer.android.com/guide/playcore/in-app-review). The extension was originally created by [AGulev](https://www.github.com/AGulev) and kindly transferred to the Defold Foundation. 6 | 7 | [Manual, API and setup instructions](https://www.defold.com/extension-review/) is available on the official Defold site. 8 | -------------------------------------------------------------------------------- /docs/example_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/extension-review/fd097b14673b3464273576b52d0faa4c760de6e6/docs/example_image.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Defold review and rating extension API documentation 3 | brief: This manual covers how to setup and use iOS and Android native review and rating popups in Defold. 4 | --- 5 | 6 | # Defold review and rating extension API documentation 7 | 8 | Defold [native extension](https://www.defold.com/manuals/extensions/) which allows the use of [native iOS Ratings and Reviews window](https://developer.apple.com/ios/human-interface-guidelines/system-capabilities/ratings-and-reviews/) and [Google Play In-App Review API](https://developer.android.com/guide/playcore/in-app-review). 9 | 10 | ## Installation 11 | To use this library in your Defold project, add the following URL to your `game.project` dependencies: 12 | 13 | [https://github.com/defold/extension-review/archive/master.zip](https://github.com/defold/extension-review/archive/master.zip) 14 | 15 | We recommend using a link to a zip file of a [specific release](https://github.com/defold/extension-review/releases). 16 | 17 | ## Example 18 | ![screenshot iOS](example_image.png) 19 | ![Screenshot android](https://user-images.githubusercontent.com/2209596/95632078-26a1d400-0a85-11eb-8d34-e25ec25d8b29.png) 20 | 21 | ```lua 22 | if (review and review.is_supported()) then 23 | review.request_review() 24 | else 25 | --do something else 26 | end 27 | ``` 28 | 29 | 30 | ## Source code 31 | 32 | The source code is available on [GitHub](https://github.com/defold/extension-review) 33 | 34 | 35 | ## API reference 36 | -------------------------------------------------------------------------------- /example/imgs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/extension-review/fd097b14673b3464273576b52d0faa4c760de6e6/example/imgs/logo.png -------------------------------------------------------------------------------- /example/main.collection: -------------------------------------------------------------------------------- 1 | name: "main" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "logo" 5 | data: "embedded_components {\n" 6 | " id: \"sprite\"\n" 7 | " type: \"sprite\"\n" 8 | " data: \"tile_set: \\\"/example/review.atlas\\\"\\n" 9 | "default_animation: \\\"logo\\\"\\n" 10 | "material: \\\"/builtins/materials/sprite.material\\\"\\n" 11 | "blend_mode: BLEND_MODE_ALPHA\\n" 12 | "\"\n" 13 | " position {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " }\n" 18 | " rotation {\n" 19 | " x: 0.0\n" 20 | " y: 0.0\n" 21 | " z: 0.0\n" 22 | " w: 1.0\n" 23 | " }\n" 24 | "}\n" 25 | "" 26 | position { 27 | x: 480.0 28 | y: 441.949 29 | z: 0.0 30 | } 31 | rotation { 32 | x: 0.0 33 | y: 0.0 34 | z: 0.0 35 | w: 1.0 36 | } 37 | scale3 { 38 | x: 1.0 39 | y: 1.0 40 | z: 1.0 41 | } 42 | } 43 | embedded_instances { 44 | id: "info" 45 | data: "components {\n" 46 | " id: \"timer\"\n" 47 | " component: \"/example/timer.script\"\n" 48 | " position {\n" 49 | " x: 0.0\n" 50 | " y: 0.0\n" 51 | " z: 0.0\n" 52 | " }\n" 53 | " rotation {\n" 54 | " x: 0.0\n" 55 | " y: 0.0\n" 56 | " z: 0.0\n" 57 | " w: 1.0\n" 58 | " }\n" 59 | "}\n" 60 | "embedded_components {\n" 61 | " id: \"supported\"\n" 62 | " type: \"label\"\n" 63 | " data: \"size {\\n" 64 | " x: 128.0\\n" 65 | " y: 32.0\\n" 66 | " z: 0.0\\n" 67 | " w: 0.0\\n" 68 | "}\\n" 69 | "scale {\\n" 70 | " x: 2.0\\n" 71 | " y: 2.0\\n" 72 | " z: 1.0\\n" 73 | " w: 0.0\\n" 74 | "}\\n" 75 | "color {\\n" 76 | " x: 0.0\\n" 77 | " y: 0.0\\n" 78 | " z: 0.0\\n" 79 | " w: 1.0\\n" 80 | "}\\n" 81 | "outline {\\n" 82 | " x: 0.0\\n" 83 | " y: 0.0\\n" 84 | " z: 0.0\\n" 85 | " w: 1.0\\n" 86 | "}\\n" 87 | "shadow {\\n" 88 | " x: 0.0\\n" 89 | " y: 0.0\\n" 90 | " z: 0.0\\n" 91 | " w: 1.0\\n" 92 | "}\\n" 93 | "leading: 1.0\\n" 94 | "tracking: 0.0\\n" 95 | "pivot: PIVOT_CENTER\\n" 96 | "blend_mode: BLEND_MODE_ALPHA\\n" 97 | "line_break: false\\n" 98 | "text: \\\"\\\\n" 99 | "\\\"\\n" 100 | " \\\"\\\"\\n" 101 | "font: \\\"/example/review.font\\\"\\n" 102 | "material: \\\"/builtins/fonts/label-df.material\\\"\\n" 103 | "\"\n" 104 | " position {\n" 105 | " x: 480.0\n" 106 | " y: 616.0\n" 107 | " z: 0.0\n" 108 | " }\n" 109 | " rotation {\n" 110 | " x: 0.0\n" 111 | " y: 0.0\n" 112 | " z: 0.0\n" 113 | " w: 1.0\n" 114 | " }\n" 115 | "}\n" 116 | "embedded_components {\n" 117 | " id: \"label1\"\n" 118 | " type: \"label\"\n" 119 | " data: \"size {\\n" 120 | " x: 128.0\\n" 121 | " y: 32.0\\n" 122 | " z: 0.0\\n" 123 | " w: 0.0\\n" 124 | "}\\n" 125 | "scale {\\n" 126 | " x: 2.0\\n" 127 | " y: 2.0\\n" 128 | " z: 1.0\\n" 129 | " w: 0.0\\n" 130 | "}\\n" 131 | "color {\\n" 132 | " x: 0.0\\n" 133 | " y: 0.0\\n" 134 | " z: 0.0\\n" 135 | " w: 1.0\\n" 136 | "}\\n" 137 | "outline {\\n" 138 | " x: 0.0\\n" 139 | " y: 0.0\\n" 140 | " z: 0.0\\n" 141 | " w: 1.0\\n" 142 | "}\\n" 143 | "shadow {\\n" 144 | " x: 0.0\\n" 145 | " y: 0.0\\n" 146 | " z: 0.0\\n" 147 | " w: 1.0\\n" 148 | "}\\n" 149 | "leading: 1.0\\n" 150 | "tracking: 0.0\\n" 151 | "pivot: PIVOT_CENTER\\n" 152 | "blend_mode: BLEND_MODE_ALPHA\\n" 153 | "line_break: false\\n" 154 | "text: \\\"\\\\n" 155 | "\\\"\\n" 156 | " \\\"\\\"\\n" 157 | "font: \\\"/example/review.font\\\"\\n" 158 | "material: \\\"/builtins/fonts/label-df.material\\\"\\n" 159 | "\"\n" 160 | " position {\n" 161 | " x: 480.0\n" 162 | " y: 535.0\n" 163 | " z: 0.0\n" 164 | " }\n" 165 | " rotation {\n" 166 | " x: 0.0\n" 167 | " y: 0.0\n" 168 | " z: 0.0\n" 169 | " w: 1.0\n" 170 | " }\n" 171 | "}\n" 172 | "" 173 | position { 174 | x: 0.0 175 | y: 0.0 176 | z: 0.0 177 | } 178 | rotation { 179 | x: 0.0 180 | y: 0.0 181 | z: 0.0 182 | w: 1.0 183 | } 184 | scale3 { 185 | x: 1.0 186 | y: 1.0 187 | z: 1.0 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /example/review.atlas: -------------------------------------------------------------------------------- 1 | images { 2 | image: "/example/imgs/logo.png" 3 | } 4 | margin: 0 5 | extrude_borders: 0 6 | inner_padding: 0 7 | -------------------------------------------------------------------------------- /example/review.font: -------------------------------------------------------------------------------- 1 | font: "/builtins/fonts/vera_mo_bd.ttf" 2 | material: "/builtins/fonts/font-df.material" 3 | size: 20 4 | antialias: 1 5 | alpha: 1.0 6 | outline_alpha: 0.0 7 | outline_width: 0.0 8 | shadow_alpha: 0.0 9 | shadow_blur: 0 10 | shadow_x: 0.0 11 | shadow_y: 0.0 12 | extra_characters: "" 13 | output_format: TYPE_DISTANCE_FIELD 14 | all_chars: false 15 | cache_width: 0 16 | cache_height: 0 17 | render_mode: MODE_SINGLE_LAYER 18 | -------------------------------------------------------------------------------- /example/timer.script: -------------------------------------------------------------------------------- 1 | function init(self) 2 | msg.post("@render:", "use_fixed_fit_projection") 3 | go.animate("logo", "position.y", go.PLAYBACK_LOOP_PINGPONG, 123, go.EASING_INSINE, 1) 4 | 5 | 6 | msg.post("@render:", "clear_color", { color = vmath.vector4(1,1,1,1)}) 7 | 8 | label.set_text("#supported", "is_supported ".. tostring(((review and review.is_supported()) or "false"))) 9 | 10 | timer.delay(3, false, function() 11 | label.set_text("#label1", "Show") 12 | if (review and review.is_supported()) then 13 | review.request_review() 14 | else 15 | --do something else 16 | end 17 | end) 18 | end -------------------------------------------------------------------------------- /game.project: -------------------------------------------------------------------------------- 1 | [project] 2 | title = review 3 | version = 3.0 4 | dependencies = 5 | 6 | [bootstrap] 7 | main_collection = /example/main.collectionc 8 | 9 | [input] 10 | game_binding = /input/game.input_bindingc 11 | 12 | [script] 13 | shared_state = 1 14 | 15 | [library] 16 | include_dirs = review 17 | 18 | [ios] 19 | bundle_identifier = com.defold.extension.review 20 | app_icon_120x120 = /example/imgs/logo.png 21 | app_icon_180x180 = /example/imgs/logo.png 22 | app_icon_76x76 = /example/imgs/logo.png 23 | app_icon_152x152 = /example/imgs/logo.png 24 | app_icon_57x57 = /example/imgs/logo.png 25 | app_icon_114x114 = /example/imgs/logo.png 26 | app_icon_72x72 = /example/imgs/logo.png 27 | app_icon_144x144 = /example/imgs/logo.png 28 | app_icon_167x167 = /example/imgs/logo.png 29 | 30 | [android] 31 | package = com.defold.extension.review 32 | 33 | [osx] 34 | bundle_identifier = com.defold.extension.review 35 | 36 | [display] 37 | dynamic_orientation = 1 38 | -------------------------------------------------------------------------------- /input/game.input_binding: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/extension-review/fd097b14673b3464273576b52d0faa4c760de6e6/input/game.input_binding -------------------------------------------------------------------------------- /review/api/api.script_api: -------------------------------------------------------------------------------- 1 | - name: review 2 | type: table 3 | desc: Functions and constants for interacting with review APIs 4 | 5 | members: 6 | 7 | #***************************************************************************************************** 8 | 9 | - name: request_review 10 | type: function 11 | desc: Open native review/rating popup 12 | 13 | #***************************************************************************************************** 14 | 15 | - name: is_supported 16 | type: function 17 | desc: Available only on iOS 10.3+. Android 5.0+ (API 21+) and the Google Play Store has to be installed. 18 | 19 | #***************************************************************************************************** 20 | 21 | -------------------------------------------------------------------------------- /review/ext.manifest: -------------------------------------------------------------------------------- 1 | name: "review" 2 | 3 | platforms: 4 | arm64-ios: 5 | context: 6 | frameworks: ["StoreKit"] 7 | 8 | armv7-ios: 9 | context: 10 | frameworks: ["StoreKit"] 11 | 12 | x86_64-ios: 13 | context: 14 | frameworks: ["StoreKit"] 15 | -------------------------------------------------------------------------------- /review/manifests/android/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation 'com.google.android.play:review:2.0.0' 3 | } 4 | -------------------------------------------------------------------------------- /review/src/android/ReviewAndroid.cpp: -------------------------------------------------------------------------------- 1 | #if defined(DM_PLATFORM_ANDROID) 2 | #include "../private_review.h" 3 | #include "jni.h" 4 | 5 | namespace ext_review { 6 | 7 | const char* JAR_PATH = "com/defold/review/Review"; 8 | 9 | bool isSupported() { 10 | ThreadAttacher attacher; 11 | JNIEnv *env = attacher.env; 12 | jclass cls = ClassLoader(env).load(JAR_PATH); 13 | jmethodID method = env->GetStaticMethodID(cls, "isSupported", "(Landroid/app/Activity;)Z"); 14 | jboolean return_value = (jboolean)env->CallStaticBooleanMethod(cls, 15 | method, dmGraphics::GetNativeAndroidActivity()); 16 | 17 | return JNI_TRUE == return_value; 18 | } 19 | 20 | void requestReview() { 21 | ThreadAttacher attacher; 22 | JNIEnv *env = attacher.env; 23 | jclass cls = ClassLoader(env).load(JAR_PATH); 24 | jmethodID method = env->GetStaticMethodID(cls, "requestReview", "(Landroid/app/Activity;)V"); 25 | env->CallStaticVoidMethod(cls, method, dmGraphics::GetNativeAndroidActivity()); 26 | } 27 | 28 | }//namespace 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /review/src/android/java/com/defold/review/Review.java: -------------------------------------------------------------------------------- 1 | package com.defold.review; 2 | 3 | import android.app.Activity; 4 | import android.os.Build; 5 | 6 | import com.google.android.play.core.review.ReviewInfo; 7 | import com.google.android.play.core.review.ReviewManager; 8 | import com.google.android.play.core.review.ReviewManagerFactory; 9 | import com.google.android.gms.tasks.Task; 10 | import com.google.android.gms.tasks.OnCompleteListener; 11 | 12 | public class Review { 13 | 14 | public static void requestReview(final Activity appActivity) { 15 | final ReviewManager manager = ReviewManagerFactory.create(appActivity); 16 | Task request = manager.requestReviewFlow(); 17 | request.addOnCompleteListener(new OnCompleteListener() { 18 | @Override 19 | public void onComplete(Task reviewTask){ 20 | if(reviewTask.isSuccessful()) { 21 | ReviewInfo reviewInfo = reviewTask.getResult(); 22 | 23 | manager.launchReviewFlow(appActivity, reviewInfo); 24 | } 25 | } 26 | }); 27 | } 28 | 29 | public static boolean isSupported(final Activity appActivity) { 30 | if (Build.VERSION.SDK_INT >= 21) { 31 | try { 32 | appActivity.getPackageManager().getPackageInfo("com.android.vending", 0); 33 | return true; 34 | } catch (Exception e) { 35 | return false; 36 | } 37 | } 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /review/src/android/jni.h: -------------------------------------------------------------------------------- 1 | #if defined(DM_PLATFORM_ANDROID) 2 | #include 3 | #include 4 | 5 | namespace ext_review { 6 | 7 | struct ThreadAttacher { 8 | JNIEnv *env; 9 | bool has_attached; 10 | ThreadAttacher() : env(NULL), has_attached(false) { 11 | if (dmGraphics::GetNativeAndroidJavaVM()->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { 12 | dmGraphics::GetNativeAndroidJavaVM()->AttachCurrentThread(&env, NULL); 13 | has_attached = true; 14 | } 15 | } 16 | ~ThreadAttacher() { 17 | if (has_attached) { 18 | if (env->ExceptionCheck()) { 19 | env->ExceptionDescribe(); 20 | } 21 | env->ExceptionClear(); 22 | dmGraphics::GetNativeAndroidJavaVM()->DetachCurrentThread(); 23 | } 24 | } 25 | }; 26 | 27 | struct ClassLoader { 28 | private: 29 | JNIEnv *env; 30 | jobject class_loader_object; 31 | jmethodID find_class; 32 | public: 33 | ClassLoader(JNIEnv *env) : env(env) { 34 | jclass activity_class = env->FindClass("android/app/NativeActivity"); 35 | jmethodID get_class_loader = env->GetMethodID(activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;"); 36 | class_loader_object = env->CallObjectMethod(dmGraphics::GetNativeAndroidActivity(), get_class_loader); 37 | jclass class_loader = env->FindClass("java/lang/ClassLoader"); 38 | find_class = env->GetMethodID(class_loader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); 39 | env->DeleteLocalRef(activity_class); 40 | env->DeleteLocalRef(class_loader); 41 | } 42 | ~ClassLoader() { 43 | env->DeleteLocalRef(class_loader_object); 44 | } 45 | jclass load(const char *class_name) { 46 | jstring str_class_name = env->NewStringUTF(class_name); 47 | jclass loaded_class = (jclass)env->CallObjectMethod(class_loader_object, find_class, str_class_name); 48 | env->DeleteLocalRef(str_class_name); 49 | return loaded_class; 50 | } 51 | }; 52 | 53 | } // namespace 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /review/src/ios/ReviewIOS.mm: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(DM_PLATFORM_IOS) 4 | #include "../private_review.h" 5 | #include 6 | 7 | namespace ext_review { 8 | 9 | static Class getClass_SKStoreReviewController() { 10 | // Cache the class in a static var 11 | static const Class SKStoreReviewController_ = NSClassFromString(@"SKStoreReviewController"); 12 | return SKStoreReviewController_; 13 | } 14 | 15 | bool isSupported() { 16 | Class SKStoreReviewController_ = getClass_SKStoreReviewController(); 17 | return !!SKStoreReviewController_; 18 | } 19 | 20 | void requestReview() { 21 | Class SKStoreReviewController_ = getClass_SKStoreReviewController(); 22 | if (SKStoreReviewController_) { 23 | [SKStoreReviewController_ performSelector:@selector(requestReview)]; 24 | } 25 | } 26 | 27 | }//namespace 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /review/src/private_review.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_ANDROID) 3 | 4 | namespace ext_review { 5 | 6 | bool isSupported(); 7 | void requestReview(); 8 | 9 | } // namespace 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /review/src/review.cpp: -------------------------------------------------------------------------------- 1 | #define EXTENSION_NAME review 2 | #define LIB_NAME "review" 3 | #define MODULE_NAME "review" 4 | 5 | #ifndef DLIB_LOG_DOMAIN 6 | #define DLIB_LOG_DOMAIN LIB_NAME 7 | #endif 8 | #include 9 | 10 | #if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_ANDROID) 11 | #include "private_review.h" 12 | 13 | namespace ext_review { 14 | 15 | static int IsSupported(lua_State* L) { 16 | bool status = isSupported(); 17 | lua_pushboolean(L, status); 18 | return 1; 19 | } 20 | 21 | static int RequestReview(lua_State* L) { 22 | requestReview(); 23 | return 0; 24 | } 25 | 26 | static const luaL_reg Module_methods[] = 27 | { 28 | {"isSupported", IsSupported}, 29 | {"requestReview", RequestReview}, 30 | {"is_supported", IsSupported}, 31 | {"request_review", RequestReview}, 32 | {0, 0} 33 | }; 34 | 35 | static void LuaInit(lua_State* L) 36 | { 37 | int top = lua_gettop(L); 38 | luaL_register(L, MODULE_NAME, Module_methods); 39 | lua_pop(L, 1); 40 | assert(top == lua_gettop(L)); 41 | } 42 | 43 | }// namespace 44 | 45 | dmExtension::Result AppInitializeReview(dmExtension::AppParams* params) 46 | { 47 | return dmExtension::RESULT_OK; 48 | } 49 | 50 | dmExtension::Result InitializeReview(dmExtension::Params* params) 51 | { 52 | ext_review::LuaInit(params->m_L); 53 | return dmExtension::RESULT_OK; 54 | } 55 | 56 | dmExtension::Result AppFinalizeReview(dmExtension::AppParams* params) 57 | { 58 | return dmExtension::RESULT_OK; 59 | } 60 | 61 | dmExtension::Result FinalizeReview(dmExtension::Params* params) 62 | { 63 | return dmExtension::RESULT_OK; 64 | } 65 | 66 | static dmExtension::Result UpdateReview(dmExtension::Params* params) 67 | { 68 | return dmExtension::RESULT_OK; 69 | } 70 | 71 | #else // unsupported platforms 72 | 73 | dmExtension::Result AppInitializeReview(dmExtension::AppParams* params) 74 | { 75 | return dmExtension::RESULT_OK; 76 | } 77 | 78 | dmExtension::Result InitializeReview(dmExtension::Params* params) 79 | { 80 | dmLogWarning("Registered %s (null) Extension\n", MODULE_NAME); 81 | return dmExtension::RESULT_OK; 82 | } 83 | 84 | dmExtension::Result AppFinalizeReview(dmExtension::AppParams* params) 85 | { 86 | return dmExtension::RESULT_OK; 87 | } 88 | 89 | dmExtension::Result FinalizeReview(dmExtension::Params* params) 90 | { 91 | return dmExtension::RESULT_OK; 92 | } 93 | 94 | static dmExtension::Result UpdateReview(dmExtension::Params* params) 95 | { 96 | return dmExtension::RESULT_OK; 97 | } 98 | #endif 99 | 100 | 101 | DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeReview, AppFinalizeReview, InitializeReview, UpdateReview, 0, FinalizeReview) 102 | --------------------------------------------------------------------------------