diff --git a/README.md b/README.md
index 737bb1a6..32035799 100644
--- a/README.md
+++ b/README.md
@@ -23,10 +23,10 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele
* **Easy to use**: `TDLib` takes care of all network implementation details, encryption and local data storage.
* **High-performance**: in the [Telegram Bot API](https://core.telegram.org/bots/api), each `TDLib` instance handles more than 18000 active bots simultaneously.
* **Well-documented**: all `TDLib` API methods and public interfaces are fully documented.
-* **Consistent**: `TDLib` guarantees that all updates will be delivered in the right order.
+* **Consistent**: `TDLib` guarantees that all updates are delivered in the right order.
* **Reliable**: `TDLib` remains stable on slow and unstable Internet connections.
* **Secure**: all local data is encrypted using a user-provided encryption key.
-* **Fully-asynchronous**: requests to `TDLib` don't block each other or anything else, responses will be sent when they are available.
+* **Fully-asynchronous**: requests to `TDLib` don't block each other or anything else, responses are sent when they are available.
## Examples and documentation
diff --git a/td/tl/tl_jni_object.cpp b/td/tl/tl_jni_object.cpp
index 7c081d14..ab685f82 100644
--- a/td/tl/tl_jni_object.cpp
+++ b/td/tl/tl_jni_object.cpp
@@ -76,6 +76,22 @@ void register_native_method(JNIEnv *env, jclass clazz, std::string name, std::st
}
}
+std::unique_ptr get_jni_env(JavaVM *java_vm, jint jni_version) {
+ JNIEnv *env = nullptr;
+ if (java_vm->GetEnv(reinterpret_cast(&env), jni_version) == JNI_EDETACHED) {
+#ifdef JDK1_2 // if not Android JNI
+ auto p_env = reinterpret_cast(&env);
+#else
+ auto p_env = &env;
+#endif
+ java_vm->AttachCurrentThread(p_env, nullptr);
+ } else {
+ java_vm = nullptr;
+ }
+
+ return std::unique_ptr(env, JvmThreadDetacher(java_vm));
+}
+
void init_vars(JNIEnv *env, const char *td_api_java_package) {
BooleanClass = get_jclass(env, "java/lang/Boolean");
IntegerClass = get_jclass(env, "java/lang/Integer");
diff --git a/td/tl/tl_jni_object.h b/td/tl/tl_jni_object.h
index 4c65e90e..d32ed75b 100644
--- a/td/tl/tl_jni_object.h
+++ b/td/tl/tl_jni_object.h
@@ -39,6 +39,37 @@ jfieldID get_field_id(JNIEnv *env, jclass clazz, const char *name, const char *s
void register_native_method(JNIEnv *env, jclass clazz, std::string name, std::string signature, void *function_ptr);
+class JvmThreadDetacher {
+ JavaVM *java_vm_;
+
+ void detach() {
+ if (java_vm_ != nullptr) {
+ java_vm_->DetachCurrentThread();
+ java_vm_ = nullptr;
+ }
+ }
+
+ public:
+ explicit JvmThreadDetacher(JavaVM *java_vm): java_vm_(java_vm) {
+ }
+
+ JvmThreadDetacher(const JvmThreadDetacher &other) = delete;
+ JvmThreadDetacher &operator=(const JvmThreadDetacher &other) = delete;
+ JvmThreadDetacher(JvmThreadDetacher &&other): java_vm_(other.java_vm_) {
+ other.java_vm_ = nullptr;
+ }
+ JvmThreadDetacher &operator=(JvmThreadDetacher &&other) = delete;
+ ~JvmThreadDetacher() {
+ detach();
+ }
+
+ void operator()(JNIEnv *env) {
+ detach();
+ }
+};
+
+std::unique_ptr get_jni_env(JavaVM *java_vm, jint jni_version);
+
std::string fetch_string(JNIEnv *env, jobject o, jfieldID id);
inline jobject fetch_object(JNIEnv *env, const jobject &o, const jfieldID &id) {