Skip to content

Commit

Permalink
feat: ios feature set (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
hyochan authored Jul 3, 2024
1 parent 3324d4b commit 4144344
Show file tree
Hide file tree
Showing 21 changed files with 20,056 additions and 30,733 deletions.
10 changes: 10 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
opt_in_rules:
- vertical_whitespace_between_cases
- vertical_whitespace_closing_braces
- vertical_whitespace_opening_braces
- vertical_parameter_alignment_on_call
- operator_usage_whitespace
- redundant_type_annotation

vertical_whitespace_closing_braces: true
vertical_whitespace_opening_braces: true
58 changes: 31 additions & 27 deletions android/src/main/java/expo/modules/iap/ExpoIapModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,39 @@ import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition

class ExpoIapModule : Module() {
// Each module class must implement the definition function. The definition consists of components
// that describes the module's functionality and behavior.
// See https://docs.expo.dev/modules/module-api for more details about available components.
override fun definition() = ModuleDefinition {
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
// The module will be accessible from `requireNativeModule('ExpoIap')` in JavaScript.
Name("ExpoIap")
// Each module class must implement the definition function. The definition consists of components
// that describes the module's functionality and behavior.
// See https://docs.expo.dev/modules/module-api for more details about available components.
override fun definition() =
ModuleDefinition {
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
// The module will be accessible from `requireNativeModule('ExpoIap')` in JavaScript.
Name("ExpoIap")

// Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
Constants(
"PI" to Math.PI
)
// Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
Constants(
"PI" to Math.PI,
)

// Defines event names that the module can send to JavaScript.
Events("onChange")
// Defines event names that the module can send to JavaScript.
Events("onChange")

// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
Function("hello") {
"Hello world! 👋"
}
// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
Function("hello") {
"Hello world! 👋"
}

// Defines a JavaScript function that always returns a Promise and whose native code
// is by default dispatched on the different thread than the JavaScript runtime runs on.
AsyncFunction("setValueAsync") { value: String ->
// Send an event to JavaScript.
sendEvent("onChange", mapOf(
"value" to value
))
}
}
// Defines a JavaScript function that always returns a Promise and whose native code
// is by default dispatched on the different thread than the JavaScript runtime runs on.
AsyncFunction("setValueAsync") { value: String ->
// Send an event to JavaScript.
sendEvent(
"onChange",
mapOf(
"value" to value,
),
)
}
}
}
Binary file added bun.lockb
Binary file not shown.
107 changes: 99 additions & 8 deletions example/App.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,111 @@
import { StyleSheet, Text, View } from 'react-native';
import * as ExpoIap from "expo-iap";
import { useState } from "react";
import {
Platform,
Pressable,
SafeAreaView,
StyleSheet,
Text,
View,
} from "react-native";

import * as ExpoIap from 'expo-iap';
import { Product } from "../src/ExpoIap.types";

const productSkus = Platform.select({
ios: ["com.cooni.point1000", "com.cooni.point5000"],

android: [
"android.test.purchased",
"android.test.canceled",
"android.test.refunded",
"android.test.item_unavailable",
],

default: [],
}) as string[];

const operations = ["initConnection", "getItems", "endConnection"];
type Operation = (typeof operations)[number];

export default function App() {
const [items, setItems] = useState<Product[]>([]);

const handleOperation = async (operation: Operation) => {
if (operation === "initConnection") {
console.log("Connected", await ExpoIap.initConnection());
return;
}

if (operation === "endConnection") {
const result = await ExpoIap.endConnection();

if (result) {
setItems([]);
}
}

if (operation === "getItems") {
try {
const items = await ExpoIap.getItems(productSkus);
setItems(items);
} catch (error) {
console.error(error);
}
}
};

return (
<View style={styles.container}>
<Text>{ExpoIap.hello()}</Text>
</View>
<SafeAreaView style={styles.container}>
<Text style={styles.title}>Expo IAP Example</Text>
<View style={styles.buttonsWrapper}>
{operations.map((operation) => (
<Pressable key={operation} onPress={() => handleOperation(operation)}>
<View style={styles.buttonView}>
<Text>{operation}</Text>
</View>
</Pressable>
))}
</View>
<View style={styles.content}>
{items.map((item) => (
<Text key={item.id}>
{item.displayName} - {item.displayPrice} ({item.currency})
</Text>
))}
</View>
</SafeAreaView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: "#fff",
alignItems: "center",
},
title: {
marginTop: 24,
fontSize: 20,
fontWeight: "bold",
},
buttonsWrapper: {
padding: 24,
alignSelf: "stretch",

flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
},
buttonView: {
borderRadius: 8,
borderWidth: 1,
borderColor: "#000",
padding: 8,
},
content: {
flex: 1,
alignSelf: "stretch",
padding: 24,
gap: 12,
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,58 @@ package com.dooboolab.test

import android.os.Build
import android.os.Bundle

import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate

import expo.modules.ReactActivityDelegateWrapper

class MainActivity : ReactActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen.
setTheme(R.style.AppTheme);
super.onCreate(null)
}

/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "main"

/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate {
return ReactActivityDelegateWrapper(
this,
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
object : DefaultReactActivityDelegate(
this,
mainComponentName,
fabricEnabled
){})
}

/**
* Align the back button behavior with Android S
* where moving root activities to background instead of finishing activities.
* @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
*/
override fun invokeDefaultOnBackPressed() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
if (!moveTaskToBack(false)) {
// For non-root activities, use the default implementation to finish them.
super.invokeDefaultOnBackPressed()
}
return
}

// Use the default back button implementation on Android S
// because it's doing more than [Activity.moveTaskToBack] in fact.
super.invokeDefaultOnBackPressed()
}
override fun onCreate(savedInstanceState: Bundle?) {
// Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen.
setTheme(R.style.AppTheme)
super.onCreate(null)
}

/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "main"

/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate =
ReactActivityDelegateWrapper(
this,
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
object : DefaultReactActivityDelegate(
this,
mainComponentName,
fabricEnabled,
) {},
)

/**
* Align the back button behavior with Android S
* where moving root activities to background instead of finishing activities.
* @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
*/
override fun invokeDefaultOnBackPressed() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
if (!moveTaskToBack(false)) {
// For non-root activities, use the default implementation to finish them.
super.invokeDefaultOnBackPressed()
}
return
}

// Use the default back button implementation on Android S
// because it's doing more than [Activity.moveTaskToBack] in fact.
super.invokeDefaultOnBackPressed()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,54 @@ package com.dooboolab.test

import android.app.Application
import android.content.res.Configuration

import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.soloader.SoLoader

import expo.modules.ApplicationLifecycleDispatcher
import expo.modules.ReactNativeHostWrapper

class MainApplication : Application(), ReactApplication {

override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
this,
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return PackageList(this).packages
}

override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"

override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
)

override val reactHost: ReactHost
get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)

override fun onCreate() {
super.onCreate()
SoLoader.init(this, false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
class MainApplication :
Application(),
ReactApplication {
override val reactNativeHost: ReactNativeHost =
ReactNativeHostWrapper(
this,
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return PackageList(this).packages
}

override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"

override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
},
)

override val reactHost: ReactHost
get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)

override fun onCreate() {
super.onCreate()
SoLoader.init(this, false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
ApplicationLifecycleDispatcher.onApplicationCreate(this)
}
ApplicationLifecycleDispatcher.onApplicationCreate(this)
}

override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
}
}
Loading

0 comments on commit 4144344

Please sign in to comment.